chengjf 发布的文章

在官方github中的issue-482中介绍了使用tt命令获取执行现场,然后用ognl获取spring的ApplicationContext从而为所欲为的示例。

在spring的生态中,如果可以获取到ApplicationContext,无疑真的可以为所欲为了。

但是在实际使用的,我发现这个获取途径有如下两个问题:

  1. 需要触发才能获取到执行现场,从而进行后续的步骤。这意味着你的应用必须提供一个类似于http接口的形式。
  2. 在多classloader的应用中,使用tt命令执行ognl表达式的时候,会出现ClassNotFound的错误,是因为classloader不对的问题,但是tt命令无法指定classloader

为了解决上述两个问题,只能使用一个类静态变量保存这个ApplicationContext,然后直接使用ongl命令去操作,ognl命令是可以使用-c参数指定classloader的。当然这个方法的缺陷就是侵入了应用。

下面附一个我用的保存ApplicationContext的示例:

package com.chengjf.example.context;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component("contextHolder")
public class ContextHolder {

    public static ApplicationContext context;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }

}

这样,就可以直接使用ognl表达式为所欲为了。

第一步,获取合适的classloader,使用sc命令:

sc -d com.chengjf.example.context.ContextHolder

结果中可能有多个classloader,根据class-loader选择合适的classloader,记住classLoaderHash

第二部,直接使用ognl表达式,获取ApplicationContext,然后获取你想要的bean,为所欲为:

ognl -c 1fe72c5c '#[email protected]@context,#o=#c.getBean("roomService"),#o.queryById(0L)'

0、无法连接jvm

错误信息如下:

com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
    at sun.tools.attach.LinuxVirtualMachine.<init>(LinuxVirtualMachine.java:106)
    at sun.tools.attach.LinuxAttachProvider.attachVirtualMachine(LinuxAttachProvider.java:78)
    at com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:250)
    at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:85)
    at com.taobao.arthas.core.Arthas.<init>(Arthas.java:28)
    at com.taobao.arthas.core.Arthas.main(Arthas.java:123)
[ERROR] attach fail, targetPid: 6958

排查思路如下:

  1. 目标pid是否正确,可以通过jps或ps进行确认
  2. 观察pid的执行用户是否和执行arthas的用户一致,比如常见的跑jvm的是tomcat用户,但是登录用户并不是

- 阅读剩余部分 -

重新定义七点半,不知道你有没有听过这个梗。
我不知道这个梗最初是来源于哪里,我第一次见是在老罗的发布会,因为老罗的发布会总会有各种各样的问题,说是七点半开,从来没有准时过,所以说,“重新定义了七点半”。

前面几篇都讲了怎么去获取数据(参数、静态字段、返回值、执行时间、执行链路),或者怎么去执行方法(静态方法、获取实例调用方法)。

这篇就说一个大招,怎么在运行时去修改代码。

0、前置工作

有下面这样一个接口,获取开始时间:


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

public interface HelloService {
    
    /**
     * 获取开始时间
     *
     * @return
     */
    String getStartTime();
}

实现是直接返回开始时间“七点半”:

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

@Service
public class HelloServiceImpl implements HelloService {
    @Override
    public String getStartTime() {
        return "七点半";
    }
}

然后整个controller调用这个getStartTime方法:

@RequestMapping("startTime")
public Object getStartTime() {
    HashMap<Object, Object> objectObjectHashMap = Maps.newHashMap();
    String result = helloService.getStartTime();
    objectObjectHashMap.put("startTime", result);
    return objectObjectHashMap;
}

返回就是说好的“七点半”:

{
    "startTime": "七点半"
}

- 阅读剩余部分 -

这次是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.

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





- 阅读剩余部分 -