chengjf 发布的文章

这次是JetBrains的最后一个谜题了。

No.0

在twitter上JetBrains发布了最后一个谜题的线索:

SGF2ZSB5b3Ugc2VlbiB0aGUgcG9zdCBvbiBvdXIgSW5zdGFncmFtIGFjY291bnQ/

这个大小写加数字加斜杠的组合,让人一下想到了base64,解一下,果然是:

Have you seen the post on our Instagram account?

No.1

去到JetBrains的ins看下,最新一条图片的标题就是“JetBrains Quest”,他的内容是:

Welcome to the final Quest! You should start on the Kotlin Playground: https://jb.gg/kotlin_quest
P.S. If you don’t know about the #JetBrainsQuest, it’s not too late to find out.

打开提示的网址 https://jb.gg/kotlin_quest,有这么一段代码:

fun main() {
   val s = "Zh#kdyh#ehhq#zrunlqj#552:#rq#wkh#ylghr#iru#wkh#iluvw#hslvrgh#ri#wkh#SksVwrup#HDS1#Li#zh#jdyh#|rx#d#foxh/#lw#zrxog#eh#hdv|#dv#sl1"

    val n: Int = TODO()
   for (c in s) {
       print(c - n)
   }
}

这个文本的样子,非常像第一个谜题中的caesar解法,然后就是这个shift要试下,最终这个shift是3,所以这个代码最终是下面这个样子:

fun main() {
    val s = "Zh#kdyh#ehhq#zrunlqj#552:#rq#wkh#ylghr#iru#wkh#iluvw#hslvrgh#ri#wkh#SksVwrup#HDS1#Li#zh#jdyh#|rx#d#foxh/#lw#zrxog#eh#hdv|#dv#sl1"

    val n: Int = 3
    for (c in s) {
        print(c - n)
    }
}

执行结果是:

We have been working 22/7 on the video for the first episode of the PhpStorm EAP. If we gave you a clue, it would be easy as pi.123


- 阅读剩余部分 -

3月11日,今天晚上到家,发现v2ex上又有人发出来JetBrains的第二道解谜了,就又参与了。

谜题是在JetBrains的twitter发布的:

Time for the next #JetBrainsQuest!
.spleh A+lrtC/dmC .thgis fo tuo si ti semitemos ,etihw si txet nehw sa drah kooL .tseretni wohs dluohs uoy ecalp a si ,dessecorp si xat hctuD erehw esac ehT .sedih tseuq fo txen eht erehw si ,deificeps era segaugnal cificeps-niamod tcudorp ehT

No.1

这段文字一看就像倒过来的,使用python进行reverse处理:

print(".spleh A+lrtC/dmC .thgis fo tuo si ti semitemos ,etihw si txet nehw sa drah kooL .tseretni wohs dluohs uoy ecalp a si ,dessecorp si xat hctuD erehw esac ehT .sedih tseuq fo txen eht erehw si ,deificeps era segaugnal cificeps-niamod tcudorp ehT"[::-1])

得到结果:

The product domain-specific languages are specified, is where the next of quest hides. The case where Dutch tax is processed, is a place you should show interest. Look hard as when text is white, sometimes it is out of sight. Cmd/Ctrl+A helps.

No.2

下一个谜题藏身于JetBrains的一款DSL工具中,参加过第一个谜题的话,应该会注意到,上次谜题中的MPS就是这个工具。打开MSP的网址:https://www.jetbrains.com/mps/

找到有关“Dutch tax”的地方,这个是一个case study,叫做“Agile Law Execution Factory”,介绍是“Domain-specific languages to implement Dutch tax legislation and process changes of that legislation.”,点击下面的“Read MPS case study”,是一个pdf文件,地址是:https://resources.jetbrains.com/storage/products/mps/docs/MPSQuest_DTO_Case_Study.pdf

下载好这个pdf文件,然后我使用chrome打开,乍一看下去,没有任何线索。但是上面的提示中,说到有些文本是白色的,使用Ctrl+A进行帮助,我就Ctrl+A然后Ctrl+C,再Ctrl+V到vscode中,发现有下面这一段话:

This is our 20th year as a company,
we have shared numbers in our JetBrains
Annual report, sharing the section with
18,650 numbers will progress your quest.

其实,这段话就位于第一页首部右侧的空白区域内。





- 阅读剩余部分 -

3月10号晚上,我在v2ex上看到了这篇帖子 《JetBrains Quest,解开可获得全家桶三个月免费订阅》 https://www.v2ex.com/t/651662,当时准备已经洗完澡,准备休息了,看到这个,勾起了我的兴趣,虽然我用的是Community的版本……

No.0

首先看第一步,给出了一串文本,如下:

48 61 76 65 20 79 6f 75 20 73 65 65 6e 20 74 68 65 20 73 6f 75 72 63 65 20 63 6f 64 65 20 6f 66 20 74 68 65 20 4a 65 74 42 72 61 69 6e 73 20 77 65 62 73 69 74 65 3f

从这个文本来看,应该是16进制的文本, 直接将这个16进制转换成文本试下:

x = '4861766520796f75207365656e2074686520736f7572636520636f6465206f6620746865204a6574427261696e7320776562736974653f'
print(bytes.fromhex(x).decode('utf-8'))

果然,结果是:

Have you seen the source code of the JetBrains website?

那就去JetBrains的官网看看

- 阅读剩余部分 -

本篇让我来体验一下ognl的强大魔法。

有这么一个场景,你的接口中有这么一个方法,清除所有的东东,让数据走上正轨。但是这个方法,你没有在后台管理系统调用,导致你现在无法调用这个方法来清除数据。

你现在怒火攻心,心急如焚,像热锅上的蚂蚁--团团转。

这个时候,ognl就派上大用场了。

但是ognl需要一个关键的对象,就是你的接口实现的对象实例,有了一个对象实例,才可以去调用这个实例的方法。那么怎么获取这个对象实例呢?

有两个方法,我来一一介绍。

一、watch命令

使用watch命令获取,watch命令里可以获取到当前观测的类实例,使用参数target就可以获取到这个类实例。

但是想被watch抓到需要其他方法触发,选择一个有http接口调用的方法作触发即可。比如下面使用sayHello方法。

watch com.chengjf.snippet.spring.mvc.service.HelloService sayHello "{target}" -x 10

结果如下:

获取到这个target,就可以调用这个target的方法了。

watch com.chengjf.snippet.spring.mvc.service.HelloService sayHello "{target.clear()}" -x 10

结果如下:

上线这个命令有个问题,就是sayHello这个方法执行多少次,那么这个clear方法就要执行多少次,这个明显不是我想要的。当然你可以在这个命令执行一次后,就马上CTRL+C结束掉。但是这个watch有个-n参数指定执行次数明显更方便一点。

watch com.chengjf.snippet.spring.mvc.service.HelloService sayHello "{target.clear()}" -x 10 -n 1

结果如下:

二、tt命令+ognl命令

tt(TimeTunnel)命令的官方说明:方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。

这个命令最厉害的是可以记录方法执行的时的现场,这样我们就可以获取到执行的对象实例了。

tt -t com.chengjf.snippet.spring.mvc.service.HelloService sayHello

调用sayHello的http接口触发,结果如下:

前面这个index,就是这个方法执行现场的编号,可以使用这个编号就行时空回溯:

tt -i 1000 -w "{target.clear()}"

结果如下:

使用-l参数可以获取到所有记录的现场:

tt -l

结果如下:

首先,有这么一个接口

package com.chengjf.snippet.spring.mvc.service;

/**
 * @author jeff.cheng
 * @date 2019-10-30 09:31
 */
public interface HelloService {

    /**
     * say hello
     *
     * @param name
     * @return
     */
    String sayHello(String name);
}

然后实现如下,里面有两个static字段,分别是HELLO_PREFIX和HELLO_SUFFIX:

package com.chengjf.snippet.spring.mvc.service.impl;

import com.chengjf.snippet.spring.mvc.service.HelloService;
import org.springframework.stereotype.Service;

/**
 * @author jeff.cheng
 * @date 2019-10-30 09:32
 */
@Service
public class HelloServiceImpl implements HelloService {

    private static String HELLO_PREFIX = "Hello, ";
    private static String HELLO_SUFFIX = "!";

    @Override
    public String sayHello(String name) {
        return HELLO_PREFIX + name + HELLO_SUFFIX;
    }
}

可以使用getstatic方法获取到static字段的值:

getstatic com.chengjf.snippet.spring.mvc.service.impl.HelloServiceImpl HELLO_PREFIX

结果如下:

可以传入通配符获取该类的所有static字段

getstatic com.chengjf.snippet.spring.mvc.service.impl.HelloServiceImpl *

结果如下:

arthas提供了ognl这个强大的工具,也可以用来获取static字段:

ognl "@[email protected]LO_PREFIX"

结果如下:

但是ognl的功能远不止如此,还可以修改static字段的值:

ognl "#[email protected]@class,#f=#c.getDeclaredField('HELLO_PREFIX'),#f.setAccessible(true),#f.set(#c,'123')"

结果如下:

查询一下,会发现值已经被修改了:

只想上面这段命令就将HELLO_PREFIX这个static字段修改成了123。下面来看下这个命令:

  1. #[email protected]@class,获取HelloServiceImpl这个class
  2. #f=#c.getDeclaredField('HELLO_PREFIX'),获取Field
  3. #f.setAccessible(true),设置Field的修改性
  4. #f.set(#c,'123'),修改字段的值为123