首页
论坛
专栏
课程

[原创]看雪CTF.TSRC 2018 团队赛_第6题WP

2018-12-12 13:55 3301

[原创]看雪CTF.TSRC 2018 团队赛_第6题WP

DCO
1
2018-12-12 13:55
3301

       程序拿到手之后,在Win10以及Win7_x86都没有跑起来,后来在Win7_x64中可以正常运行

明修栈道

       关键函数的定位好像很简单,看导入表发现GetDlgItemTextA和MessageBoxA这样的敏感函数,下断后就来了


       程序的流程看起来简单清晰,小菜就喜欢这种简单粗暴的

       仔细一看,好像有“猫腻”,没找到注册成功的提示

       看起来只有那个sub_401020()函数有可疑成分,跟进去一看,是个“空壳”。其实WinMain也是一个“空壳”

       猜测是哪里进行了代码修改之类的,对那两个全局错误提示的字符串参考引用,发现都是落在了sub_401040()这个函数内部。这就很头大了。。。


暗度陈仓

       突然间在IDA中Ctrl+E,看到了TLS回调,故事开始了…

       TLS回调中使用SMC技术,对代码进行修改



        其实关键是修改user32.GetDlgItemTextA,看看它修改前后的汇编代码变化效果

修改前的GetDlgItemTextA:


修改后的GetDlgItemTextA:


        很显然“猫腻”就出现在这个jmp指令上

        这也就是,之前F8步过GetDlgItemTextA函数时,所有的萎缩操作都完成了,给我们看到的只有“try again!”

熟悉的八数码

        跟进jmp那个跳转,来到下面这一坨,关键是那个sub_401290()

       接着跟进,看到初始化一个状态数组

bool __cdecl sub_401290(int key, int key_len)
{
	g_ary[0] = 4;
	g_ary[1] = 1;
	g_ary[2] = 3;
	g_ary[3] = 7;
	g_ary[4] = 2;
	g_ary[5] = 5;
	g_ary[6] = 8;
	g_ary[7] = 6;
	g_ary[8] = 0;
	return sub_4015B0(key, key_len);
}
        跟进sub_4015B0(key, key_len),其实看到下面这个函数就应该联想的“八数码问题”,因为之前手撸过【吾爱破解2016安全挑战赛-第一题】,不过可能当时脑子太累了,和稀泥了,没看出来
bool __cdecl sub_4015B0(int key, int key_len)
{
	int i; // [esp+0h] [ebp-Ch]
	int v4; // [esp+8h] [ebp-4h]

	v4 = 0xCCCCCCCC;
	if (key_len % 2)                             // 说明 key_len 是偶数
		return 0;
	for (i = 0; i < key_len; i += 2)
	{
		if (*(_BYTE *)(i + key) == 'w')           // 4个移动方向
			v4 = 0;
		if (*(_BYTE *)(i + key) == 'd')
			v4 = 1;
		if (*(_BYTE *)(i + key) == 's')
			v4 = 2;
		if (*(_BYTE *)(i + key) == 'a')
			v4 = 3;
		if (!sub_401380(v4, *(char *)(i + key + 1) - '0'))
			return 0;
	}
	return g_ary[0] == 1                          // 验证成功的条件
		&& g_ary[1] == 2
		&& g_ary[2] == 3
		&& g_ary[3] == 4
		&& g_ary[4] == 5
		&& g_ary[5] == 6
		&& g_ary[6] == 7
		&& g_ary[7] == 8
		&& !g_ary[8];
}

        接着跟进sub_401380()函数,这时F5就看起来有些吃力了

        还是手撸吧,老是F5容易营养不良

        其实逻辑很简单了,说来真惭愧,撸成下面这样才突然想起来是“八数码问题”,记性真是差的够呛

int sub_401380(int nDirect, int nNum)
{
	if (nNum == 0)
	{
		return 0;
	}
	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 3; ++j)
		{
			if (g_byteAry[i][j] != nNum)
			{
				continue;
			}
			switch (nDirect)
			{
			case 0:   //上w
				if (i == 0 || g_byteAry[i - 1][j] != 0)
				{
					return FALSE;
				}
				g_byteAry[i - 1][j] = g_byteAry[i][j];
				g_byteAry[i][j] = 0;
				return TRUE;
			case 1:   //右d
				if (j == 2 || g_byteAry[i][j + 1] != 0)
				{
					return FALSE;
				}
				g_byteAry[i][j + 1] = g_byteAry[i][j];
				g_byteAry[i][j] = 0;
				return TRUE;
			case 2:   //下s
				if (i == 2 || g_byteAry[i + 1][j] != 0)
				{
					return FALSE;
				}
				g_byteAry[i + 1][j] = g_byteAry[i][j];
				g_byteAry[i][j] = 0;
				return TRUE;
			case 3:   //左a
				if (j == 0 || g_byteAry[i][j - 1] != 0)
				{
					return FALSE;
				}
				g_byteAry[i][j - 1] = g_byteAry[i][j];
				g_byteAry[i][j] = 0;
				return TRUE;
			default:
			}
		}
	}
	return FALSE;
}

         八数码初始状态和目标状态,移动规则只能是“0”和它挨着的元素交换


        逆推Key,其实知道这是“八数码问题”基本上就解决了,去网上A一段别人的代码

        此处推荐:https://blog.csdn.net/GuangHEultimate/article/details/51377269

        八数码存在多解的,此处得到的是最小步数


由于八数码存在多解,CM还有一些其他的约束条件,当时就拿着上面的求解结果去了














[招聘]欢迎市场人员加入看雪学院团队!

最后于 2018-12-12 14:12 被DCO编辑 ,原因:
最新回复 (2)
我的名叫成长 2018-12-14 11:13
2
0
头皮发麻,萌新表示看不懂
petersonhz 2019-4-1 01:11
3
0
在Win10以及Win7_x86都没有跑起来,后来在Win7_x64中可以正常运行,直接在电脑上点击么,楼主不怕中毒么
游客
登录 | 注册 方可回帖
返回