聲明
- 本篇只從逆向興趣出發,研究其程序運行原理。
- CLion程序版權為jetBrains所有.
- 注冊碼授權為jetBrains及其付費用戶所有.
- 不會釋出任何完整的源代碼.
- 涉及能直接推算出注冊碼的地方打碼.
- 網上查了下,已有注冊機,所以想要key的同學不要找我.
CLion是什么?
CLion是著名的jetBrains公司出的一款C/C++智能IDE。
什么,你不知道jetBrains?
我只提兩點:
- Visual Studio ReSharper (for C#)
- IntelliJ IDEA (for java)
你還是不知道?好吧,我確定你是emacs/vim黨.
CLion如下:
背景
在上篇:CLion注冊碼算法逆向分析實錄
我們通過結合jdb、jd-gui等工具,靜態分析被混淆的clion.jar
中的class信息,順利拿到了CLion的注冊碼算法.
但是,如果能在動態調試中分析代碼路徑,拿注冊碼算法或者改改功能啥的不是更酸爽么?
本篇將從動態調試的角度展開逆向之旅,作為對上篇的一個補充。
本篇用到的關鍵技術和工具:
- java -verbose
- HotSpot™ Serviceability Agent
- jetBrains intellij IDEA 14.3
- jetBrains CLion 1.0.4
- jd-gui 1.2
- jinfo
- dump運行時的class信息
- 帶混淆調試
- ClassPath和vm options修復
動態調試的困難
對於CLion這種產品級程序,我們面臨以下困難:
- 無源碼
- 字節碼混淆
- 運行時生成class和hotswap
獲取入口函數所在的類名
辦法總比困難多,讓我們開始准備動態調試吧!
通過上一篇博文的分析,我們已經熟悉了CLion程序啟動的一些代碼路徑,首先要找到程序的入口函數main
,並重建它。怎么找呢?
- 方法1:通過啟動腳本來找
可以通過查看$CLION_HOME/bin
下的clion.sh
來看啟動參數:
133 MAIN_CLASS_NAME="$CL_MAIN_CLASS_NAME"
134 if [ -z "$MAIN_CLASS_NAME" ]; then
#注意這里
135 MAIN_CLASS_NAME="com.intellij.idea.Main"
136 fi
...
176 LD_LIBRARY_PATH="$IDE_BIN_HOME:$LD_LIBRARY_PATH" "$JDK/bin/java" \
177 $AGENT \
178 "-Xbootclasspath/a:$IDE_HOME/lib/boot.jar" \
179 -classpath "$CLASSPATH" \
180 $VM_OPTIONS "-Djb.vmOptionsFile=$VM_OPTIONS_FILES_USED" \
181 "-XX:ErrorFile=$HOME/java_error_in_CL_%p.log" \
182 -Djb.restart.code=88 -Didea.paths.selector=clion10 \
183 $IDE_PROPERTIES_PROPERTY \
184 $IDE_JVM_ARGS \
185 $REQUIRED_JVM_ARGS \
#以及這里
186 $MAIN_CLASS_NAME \
187 "$@"
188 EC=$?
- 方法2:通過jinfo來獲取
也可以讓CLion先跑起來,通過jinfo
來獲取,首先通過jps
和ps -ef | grep clion
來確認CLion的pid
:
[haoran@localhost Tools]$ jps
27120 Jps
4001 Main
26953 Main
16911 Launcher
接着輸入jinfo pid
,這里是jinfo 26953
:
[haoran@localhost Tools]$ jinfo 26953
Attaching to process ID 26953, please wait...
Error attaching to process: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 25.45-b02. Target VM is 25.40-b25
sun.jvm.hotspot.debugger.DebuggerException: sun.jvm.hotspot.runtime.VMVersionMismatchException: Supported versions are 25.45-b02. Target VM is 25.40-b25
at sun.jvm.hotspot.HotSpotAgent.setupVM(HotSpotAgent.java:435)
at sun.jvm.hotspot.HotSpotAgent.go(HotSpotAgent.java:305)
at sun.jvm.hotspot.HotSpotAgent.attach(HotSpotAgent.java:140)
at sun.jvm.hotspot.tools.Tool.start(Tool.java:185)
at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)
at sun.jvm.hotspot.tools.JInfo.main(JInfo.java:138)
發現因為jre/jvm
的版本不匹配,出現了異常,怎么解決呢?
從clion.sh
入手,看看它如何指定jvm
:
可以發現,$IDE_HOME
意即CLion安裝的路徑比$JAVA_HOME
搜索的順序更靠前,我們調整這個順序即可避免jre/jvm
版本不匹配的問題。
調整后,再次利用jinfo pid
來查看,得到如下信息:
之所以列舉jre/jvm版本不匹配的異常問題,以及通過jinfo來獲取程序入口函數所在類的方式,是為后續我們通過SA來dump運行時的class及修復java文件掃清障礙、奠定基礎。
新建入口類##
我們已經得到main
函數所在的類名為com.intellij.idea.Main
,但是通過分析,發現其不在clion.jar
中,那么它在哪里?
我們通過在CLion啟動參數中加入-verbose,並將結果重定向到文件中,來分析這個類所在的jar。
如下所示:
接下來,通過jd-gui
來反編譯bootstrap.jar/com/intellij/idea/Main.class
,並將其java代碼導入到我們新建的同名java文件中:
修復入口類##
這樣的java代碼是無法通過編譯的,而且因為很多缺失的類都是很重要的依賴,所以無法通過簡單的屏蔽來讓代碼跑起來。
那我們開始修復這些缺失的類,怎么修復呢?
我們可以使用
HotSpot™ Serviceability Agent (SA)
提供的能力,獲取運行時的class。當然,獲取運行時的class不只這一種方式。
說干就干,classFilter:
編譯好這個classFilter
,按下面的步驟來運行:
- 運行CLion.
- 找到CLion的pid.
- 啟動如下命令:
java -cp $JAVA_HOME/lib/sa-jdi.jar:. \
-Dsun.jvm.hotspot.tools.jcore.filter=$filterName \
-Dsun.jvm.hotspot.tools.jcore.outputDir=$dumpedClassOutputDir \
sun.jvm.hotspot.tools.jcore.ClassDump $clion_pid
# $filterName :我們自定義的classFilter
# $dumpedClassOutputDir : 存放dump出的class文件的目錄
# $clion_pid :CLion進程pid.
看下我們dump出的classes:
到這一步,已經成功了一大半,接下來,按照你喜歡的方式將這些classes加入classPath
吧!
修復ClassPath
還在等什么,趕緊點run
吧:
嗯,果不其然,很多類還是缺失,對於運行中生成的類,按上面的方法來找,對於已經在jar
中的類,趕緊找找classPath
還有什么吧。
還記得上面的jinfo
吧,祭出:
將這些加入ClassPath
中。
修復資源、運行時參數、及JVM的options##
程序已經越來越接近跑起來的狀態,還有一些細碎,奔跑吧騷年!
Q. 此刻有沒有一種,買來風扇,塗上硅膠,扣定開關的感覺?
A. 要的就是這種能夠DIY的工程師感覺嘛~^^
你會發現,后續的運行中,還會出現許多異常,沒有關系,通過分析,就知道還有一些東西沒有修復,包括:
- 資源/Resources
- 運行時參數
- vm options
其中CLion的vm options
我們依然通過jinfo
方式獲取:
-Xss2m -Xms256m -Xmx768m -XX:MaxPermSize=250m
-XX:ReservedCodeCacheSize=96m -XX:+UseConcMarkSweepGC
...
-XX:ErrorFile=/home/haoran/java_error_in_CL_%p.log
-Djb.restart.code=88 -Didea.paths.selector=clion10
-Didea.platform.prefix=CLion
-Didea.no.jre.check=true
讓程序動起來!##
做完了上面細碎的功夫,來看看我們的成果:
- 華麗麗的Stack Frames!
- 華麗麗的Locals!
- 華麗麗的注冊碼算法!
結語##
什么?沒有動態調試過程?
有意研究注冊碼算法的同學,請參考上篇博文:CLion注冊碼算法逆向分析實錄.但是不要做壞事哦 :]
我覺得上面的幾個華麗麗的東西已經足夠你
- step in/over/out (單步 步入/步過/跳出)
- evaluate expressions (表達式計算)
- stack frame in/out (棧幀切換)
- break point (斷點啊親)
有了這些還追不出注冊碼算法么?
騷年,那你該反思了 :]
撰文不易,若覺得本文對你有幫助或者博你一笑的,留個言、點個推薦吧 :]