首页
社区
课程
招聘
[原创][庄周梦蝶]兔斯基保护协会提供的题目解法,相关数学,可能需要的自动机
发表于: 2019-9-17 19:21 3219

[原创][庄周梦蝶]兔斯基保护协会提供的题目解法,相关数学,可能需要的自动机

2019-9-17 19:21
3219

下面有python源代码:(附件是缩进良好的源代码)

python3直接可以跑,python2也许也可以,我没用啥高级函数。

源代码第一部分是,虚拟机和题目机制解说,源代码加注释

源代码第二部分是,有效解(正确答案)的得出,解空间数学证明

源代码第三部分是,解枚举自动机


铺垫:

我的程序极小,代码很短,没加壳,可以通过IDA静态分析得到题目的代码架构如下图:



推荐判断方法:(对于有协议分析或者数据结构分析经验的选手,更容易找到关键点)

1,可以分析出虚拟指令集,只有10种指令,而且非常简练(见下文python代码)。指令集只能访问其中两块内存,其中一块是128个范围为 0-127 的数字,无重复,记作数组A;另一块是范围 0-255 的数字,但只有128个,且无重复,记作数组B.

A 和 B 在IDA中的位置见下图:dword_4143F0就是数组A,dword_413FF0就是数组B



2,看结果判定的部分知,用于和计算结果比对的是一个由128个范围 0-127 的数字组成的数组,记作数组C. 指令集不能操作数组C.

数组C在IDA中的代码位置如下图:


数组C在IDA中的内存如下图。是不是特征很明显?(我特意用int类型存放,以突出其是0-127的数组的特点。有数据结构逆向经验者,会觉得这比Offset+Length或者Length+Pointer的结构还明显,这就是个索引。当然,不需要这步就看出来,可以第3步再发现)



3,结合指令集的限制,和结果判断方式,我们主要研究A,B,C的关系,而这道题也明显应从数据特征分析入手。从A,C的构成来看,很明显有是索引的可能。用数组C的索引访问数组B,是升序排列。可见是个排序题。(总共就3块数据,来回排列组合式的看看关系,也能看到升序数列,有python代码清晰展示这三块数据的内容)

A = [29, 76, 10, 59, 66, 1, 94, 48, 6, 74, 40, 17, 81, 119, 3, 28, 2, 45, 75, 122, 126, 105, 107, 96, 36, 115, 71, 125, 64, 0, 41, 70, 9, 117, 92, 121, 7,

27, 95, 111, 78, 26, 16, 85, 104, 58, 8, 82, 124, 113, 18, 79, 99, 97, 88, 11, 24, 109, 108, 52, 46, 110, 93, 43, 30, 86, 37, 87, 31, 118, 62, 35, 38, 77, 14, 51, 47, 55, 57,20, 89, 69, 65, 39, 101, 103, 15, 60, 44, 102, 73, 23, 90, 22, 91, 13, 98, 120, 25, 19, 50, 112, 56, 42, 5, 123, 53, 127, 80, 32, 49, 34, 54, 61, 84, 83, 100, 33, 12, 114, 4, 21, 72, 116, 63, 68, 106, 67]

B = [64, 58, 59, 7, 49, 95, 141, 175, 31, 115, 45, 215, 226, 154, 250, 149, 182, 135, 187, 70, 114, 120, 105, 88, 15, 234, 18, 89, 216, 176, 75, 251, 97,

166, 46, 78, 225, 35, 124, 203, 252, 86, 138, 169, 196, 199, 238, 158, 171, 102, 177, 60, 100, 72, 82, 143, 13, 181, 210, 43, 159, 65, 222, 173, 101,

93, 168, 39, 185, 69, 79, 17, 198, 2, 61, 37, 218, 243, 133, 52, 213, 245, 4, 111, 121, 255, 20, 233, 76, 117, 40, 118, 19, 128, 241, 132, 244, 178, 62,

116, 206, 51, 148, 80, 211, 142, 204, 74, 209, 21, 230, 162, 130, 25, 190, 106, 108, 5, 249, 92, 29, 83, 155, 11, 205, 57, 248, 253]

C = [73, 82, 117, 3, 123, 56, 24, 71, 26, 92, 86, 109, 113, 120, 8, 37, 75, 67, 90, 59, 10, 34, 4, 101, 79, 125, 1, 2, 51, 74, 98, 0, 61, 69, 19, 53, 107,

30, 88, 35, 70, 103, 54, 121, 41, 23, 27, 119, 65, 5, 32, 52, 64, 49, 22, 115, 116, 83, 20, 9, 99, 89, 91, 21, 84, 38, 93, 112, 95, 78, 17, 42, 6, 105, 55, 102, 15, 13, 122, 47, 60, 111, 33, 66, 43, 48, 63, 7, 29, 50, 97, 57, 16, 68, 18, 114, 44, 72, 45, 39, 106, 124, 100, 108, 58, 104, 80, 11, 28, 76, 62, 36, 12, 110, 87, 25, 46, 94, 77, 96, 81, 126, 118, 14, 31, 40, 127, 85]

D = []

for i in C:

    D.append(B[i])

print(D) # 输出升序数列


4,由IDA分析到两重循环调用未知指令流,就知道要填写的代码仅仅是:if (比较){交换;} i++;(两重循环也是排序的特征,想到这个甚至可以跳过1、2、3步)


5,正确答案选取的是笔者认为最直接的思路,只要排序成功都能看到鼓励性输出。


6,笔者提供了自动机枚举答案的变体24640种,这些变体的大多数变体是有效但反人类的编程方式。笔者相信大多数人不需要机器枚举。

python程序只给了5个数据,原题是128个。不过,这完全不影响解法和解空间。


7,数学证明和编写思路见python程序的注释。


下面python程序正式开始:(附件是缩进良好的源代码,帖子本身难以保证缩进,诸君见谅!)


# WP By Totoro 大龙猫

# GOAL: sort the g_box

g_box = [2, 1, 3, 5, 4]

defrecover_box():

global g_box

g_box = [2, 1, 3, 5, 4]

# The followings are the test functions. Our goal is to make function "test" return True!

defsort_wrapper(func, *args):

global g_box

global g_i

loop =1

while loop <5:

g_i =1

while g_i <5:

func(*args) # this is the user input

loop = loop +1

result = g_box.copy()

for i inrange(0, 5):

result[i] = g_box[g_a[i]]

return result

deftest(func, *args):

if sort_wrapper(func, *args) != [1, 2, 3, 4, 5]:

returnFalse

returnTrue

# The following is the description of the virtual machine I designed.

# virtual registers

g_i =1

g_value =0

g_op =0

g_op1 =0

g_op2 =0

g_less_than =0

g_a = [4, 2, 1, 0, 3]

# macros

OP_ADD =0

OP_SUB =1

OP_AND =2

OP_OR =3

OP_XOR =4

OP_TEST =5

OP_MAX =6

# virtual instructions

definc():

global g_i

g_i = g_i +1

defdec():

global g_i

g_i = g_i -1

defset_op1():

global g_op1

g_op1 = g_value

defset_op2():

global g_op2

g_op2 = g_value

defload_value_i():

global g_value

g_value = g_i

defload_value_mem():

global g_value

g_value = g_a[g_value]

defload_value_box():

global g_value

g_value = g_box[g_value]

defload_op(op):

global g_op

g_op = op

defreset():

global g_less_than

g_less_than =True

defcontitional_calculate():

global g_less_than

if g_less_than:

if g_op == OP_ADD:

g_a[g_op1] += g_a[g_op2]

if g_op == OP_SUB:

g_a[g_op1] -= g_a[g_op2]

if g_op == OP_AND:

g_a[g_op1] &= g_a[g_op2]

if g_op == OP_OR:

g_a[g_op1] |= g_a[g_op2]

if g_op == OP_XOR:

g_a[g_op1] ^= g_a[g_op2]

if g_op == OP_TEST:

if g_op1 < g_op2:

g_less_than =True

elif g_op1 == g_op2:

g_less_than =False

elif g_op1 > g_op2:

g_less_than =False

# The design of the virtual machine ends.

# The cracking procedures is below.

# Here is a simple algorithm which costs about 32 bytes in virtual instructions.

defsimple_sort_kernel():

global g_i

global g_a


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

最后于 2019-9-20 13:50 被hugetotoro编辑 ,原因:
上传的附件:
收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//