刚才看到的这道挺有意思的题

到手直接丢进IDA,emmm先脱个UPX。

Ctrl + S 查看Segment
程序主体

脱壳以后再次丢进IDA,可见程序逻辑挺简单的,看起来只要输入19个“L”或者“R”组成的字符串就会计算分数,于是我们尝试一下 :

ん?(察觉

然后再仔细看了一眼,sub_41114F这个函数十分可疑,跟进去看一眼:

VirtualQueryVirtualProtect都是smjb?

吓得我赶紧打开Google问一下谷歌娘

VirtualProtect

看起来是使内存可写入。这时候我就在撕烤着到底是不是什么编译器带进去的系统函数。Google了一下该题的writeup,发现全都是这么说的:

而当我调试经过004114F这个函数过后,我输入的字符串发生了有规律的改变: 再试验几个由“H”和“V”构成的字符串后发现,004114F这个加密函数是将偶数位的L与H互换,偶数位的R与V互换。于是将原来深搜的结果进行相应的转换,便是flag中括号里的内容了。

草(日本语),说了跟没说一样。

于是决定自己用IDA的Remote Windows Debugger调一下。注意这里不用Local是因为不知道为什么,泄露版的IDA 7.0无法正常调试exe,一运行就崩。。

于是我们在sub_411750这里下断点,然后执行:

嗯???EAX指向了一个nullsub,然后对函数体异或?

于是我们在这个函数return之前下个断点,看一下之后这个nullsub变成什么样了

异或前
异或后

看起来。。这程序是把这个函数加密了。我们把原来的nullsub_1 按U undefine掉,然后按p重新parse函数,再F5,就获得了这样的东西:

嗯,这就是把输入字符串偶数位跟4异或,获得结果的函数了。

最后我们来整理下:

sub_41114F调用sub_411900,调用sub_4110A5,传递参数为被加密的函数的指针和函数体长度(0x411994-0x411953),以及异或的数值(4),sub_4110A5nullsub_1函数解密完成以后,调用他,进行真正的字符串处理。

再往后,就是分析程序后面的计算分数过程了。首先我们需要获得随机数表。看了下Import表,其调用的是VCRUNTIME140D,于是我们用VS 2017生成对应的随机数表:

#include <stdio.h>
#include <stdlib.h>

int main() {
	srand(0xCu);
	for (int i = 1; i <= 20; ++i) {
		printf("[");
		for (int j = 1; j <= i; ++j) {
			printf("%d, ", rand() % 100000);
		}
		printf("\b\b],\n");
	}
	return 0;
}

获得随机数表:

[77],
[5628, 6232],
[29052, 1558, 26150],
[12947, 29926, 11981, 22371],
[4078, 28629, 4665, 2229, 24699],
[27370, 3081, 18012, 24965, 2064, 26890],
[21054, 5225, 11777, 29853, 2956, 22439, 3341],
[31337, 14755, 5689, 24855, 4173, 32304, 292, 5344],
[15512, 12952, 1868, 10888, 19581, 13463, 32652, 3409, 28353],
[26151, 14598, 12455, 26295, 25763, 26040, 8285, 27502, 15148, 4945],
[26170, 1833, 5196, 9794, 26804, 2831, 11993, 2839, 9979, 27428, 6684],
[4616, 30265, 5752, 32051, 10443, 9240, 8095, 28084, 26285, 8838, 18784, 6547],
[7905, 8373, 19377, 18502, 27928, 13669, 25828, 30502, 28754, 32357, 2843, 5401, 10227],
[22871, 20993, 8558, 10009, 6581, 22716, 12808, 4653, 24593, 21533, 9407, 6840, 30369, 2330],
[3, 28024, 22266, 19327, 18114, 18100, 15644, 21728, 17292, 8396, 27567, 2002, 3830, 12564, 1420],
[29531, 21820, 9954, 8319, 10918, 7978, 24806, 30027, 17659, 8764, 3258, 20719, 6639, 23556, 25786, 11048],
[3544, 31948, 22, 1591, 644, 25981, 26918, 31716, 16427, 15551, 28157, 7107, 27297, 24418, 24384, 32438, 22224],
[12285, 12601, 13235, 21606, 2516, 13095, 27080, 16331, 23295, 20696, 31580, 28758, 10697, 4730, 16055, 22208, 2391, 20143],
[16325, 24537, 16778, 17119, 18198, 28537, 11813, 1490, 21034, 1978, 6451, 2174, 24812, 28772, 5283, 6429, 15484, 29353, 5942],
[7299, 6961, 32019, 24731, 29103, 17887, 17338, 26840, 13216, 8789, 12474, 24299, 19818, 18218, 14564, 31409, 5256, 31930, 26804, 9736],

然后再求最大路径,可以戳这里这里自行参考,我就不贴了

最后得到最佳路径 RRRRRLLRRRLRLRRRLRL,再根据上文提示将该路径偶数位跟4异或:

inp = bytearray(b"RRRRRLLRRRLRLRRRLRL")

for i in range(1, len(inp), 2):
    inp[i] ^= 4

print(inp)

获得flag:RVRVRHLVRVLVLVRVLVL

分类: 逆向

发表评论

电子邮件地址不会被公开。 必填项已用*标注