java程式反編譯之偷樑換柱-簡繁通4.0
目標軟體:簡繁通4.0試用版
下載地址:http://www.xdevelop.net/download/JFTV40.zip
軟體大小:236KB
軟體授權:共享軟體
加密方式:註冊碼
適用平臺:WindowsXP/2000/98/95/Me/NT(4.0)+Java(TM) 2 Runtime Environment Version
1.4.0以上
破解工具:Jbuilder9、小穎JAVA原始碼反編譯超級引摯V1.4 標準版。
文章作者:dayone
破解時間:2003-07-11夜
E-mail:dayone@wxxd.com
關於本文:本文主要目的在於教學,研究java程式的反編譯,請勿將此教程用於商業目的,否則後果自負。
首先解壓JFTV40.zip,再解開其中的JFTServer4.jar,可以看到在解壓目錄JFTServer4\net\xdevelop下是主類JFTServer.class(可以由啟動程式startJFT.bat的內容“java
-hotspot -ms64m -mx64m -classpath JFTServer4.jar net.xdevelop.JFTServer”得知。
解壓目錄JFTServer4下的class加密過了,於是反主類JFTServer.class,看一下這個檔案的原始碼,其中,“//”處是我自己加入的註釋。
//Source File Name: JFTServer.class (為省篇幅,。。。。。處程式碼省掉了)
package net.xdevelop;
。。。。。
public class JFTServer extends ClassLoader
implements ActionListener
{
。。。。。
public JFTServer(String O000O0OoO0O0OoOOOO00o[])
{
O00oo0oO0o00O0o00O000 = new Hashtable();
O0ooOooOoO00oOoO0OooO = false;
O000OOoO0O0oO0O0O0o0o = true;
O0oOOO00Oo00o0o0o00OO = null;
try
{
O00OO0000OOOoo00O0OoO = O000O0OoO0O0OoOOOO00o;
byte O00oOOOOO0OO0o000O0oO[] = Ooo0OoO000o0o0O00000o(getClass().getName());
if(O00oOOOOO0OO0o000O0oO == null)
return;
O0O0o0oO00OoOOo00oO0o = new ByteArrayInputStream(O00oOOOOO0OO0o000O0oO);
O00O00O0O0O0O000OOOo0 = O0o0O0OOOo000OOoooOOO(O0O0o0oO00OoOOo00oO0o);
if(O00O00O0O0O0O000OOOo0 < 2L)
{
System.out.println("Error:
there is something wrong with the class file " + getClass().getName());
return;
}
O0OooOo0O0OOoOOoO0Oo0();
O0OooOo0O0OOoOOoO0Oo0();
}
catch(Exception Ooooo0oO00oo0o000oOOo)
{
System.out.println("Error: "
+ Ooooo0oO00oo0o000oOOo.toString());
System.exit(0);
}
try
{
Oo0oO0000O00OOOO00oO0 = ResourceBundle.getBundle("resource.template1Resource",
Locale.getDefault(), O0Oo00OO0o0O00ooOoOoO);
}
catch(MissingResourceException Ooooo0oO00oo0o000oOOo)
{
System.out.println(Ooooo0oO00oo0o000oOOo.toString());
System.exit(0);
}
try
{
int O0Oo00ooO00Oo0o0OO0oo = O0O0o0oO00OoOOo00oO0o.read();
int OooOOoOoO0OOOO0oOO00o = O0O0o0oO00OoOOo00oO0o.read();
String O0ooOo00O00OOOo00oO00 = null;
if(O0Oo00ooO00Oo0o0OO0oo == 0)
{
O000OOoO0O0oO0O0O0o0o
= false;
} else
{
O000OOoO0O0oO0O0O0o0o
= true;
if(OooOOoOoO0OOOO0oOO00o
!= 0)
{
byte
O0oo00OOoOO0O0oOOO00o[] = new byte[16];
O0O0o0oO00OoOOo00oO0o.read(O0oo00OOoOO0O0oOOO00o);
O0ooOo00O00OOOo00oO00
= new String(O0oo00OOoOO0O0oOOO00o, "8859_1");
}
String O0OooOO0Ooo0o0O0OO000
= O0OooOo0O0OOoOOoO0Oo0();
O0OooOo0O0OOoOOoO0Oo0();
Class Oo0o0OoOO0OOoOo0oOOOO
= loadClass(O0OooOO0Ooo0o0O0OO000, true);
O0oOOO00Oo00o0o0o00OO
= Oo0o0OoOO0OOoOo0oOOOO.newInstance();
byte O0oo00OOoOO0O0oOOO00o[]
= new byte[0];
Class O0OOOOOO000o0oO0oooO0[]
= {
O0oo00OOoOO0O0oOOO00o.getClass(),
Integer.TYPE
};
O0OOOOOOo0oOO0OO0o0OO
= Oo0o0OoOO0OOoOo0oOOOO.getMethod("update", O0OOOOOO000o0oO0oooO0);
Class Oo0o0o00OO000Oo00OO0O[]
= {
OooOoO0000o0ooOOo00oo
== null ? (OooOoO0000o0ooOOo00oo = class$("java.io.InputStream"))
: OooOoO0000o0ooOOo00oo, Oo0O0OO0OoOo00O0OO00O == null ? (Oo0O0OO0OoOo00O0OO00O
= class$("java.lang.String")) :
Oo0O0OO0OoOo00O0OO00O
};
O0OoooOo0OoOoooo000oO
= Oo0o0OoOO0OOoOo0oOOOO.getMethod("init", Oo0o0o00OO000Oo00OO0O);
if(O0oOOO00Oo00o0o0o00OO
!= null && OooOOoOoO0OOOO0oOO00o != 0)
{
Object
O00O0oO0oO0o00OoOo0Oo[] = {
O0O0o0oO00OoOOo00oO0o, O0ooOo00O00OOOo00oO00
};
O0OoooOo0OoOoooo000oO.invoke(O0oOOO00Oo00o0o0o00OO,
O00O0oO0oO0o00OoOo0Oo);
}
if(OooOOoOoO0OOOO0oOO00o
== 0)
{
O0ooOooOoO00oOoO0OooO
= true;
OooOO0ooOo000oOo00OO0();
}
}
if(!O0ooOooOoO00oOoO0OooO)
Oo000OOo0ooO00o00oO0o();
}
catch(Exception Ooooo0oO00oo0o000oOOo)
{
System.out.println(Oo0oO0000O00OOOO00oO0.getString("Error:
") + Ooooo0oO00oo0o000oOOo.toString());
System.exit(0);
}
}
。。。。。
protected Class findClass(String OoO00OooOOo00o0Ooo0oo)
throws ClassNotFoundException
{
Class Oo0o0O000oOOoOOOOOoOo = null;
byte Oo00oooo0ooO000OoOOOo[] = (byte[])O00oo0oO0o00O0o00O000.get(OoO00OooOOo00o0Ooo0oo);
if(Oo00oooo0ooO000OoOOOo != null && Oo00oooo0ooO000OoOOOo.length
!= 0)
Oo0o0O000oOOoOOOOOoOo = defineClass(OoO00OooOOo00o0Ooo0oo,
Oo00oooo0ooO000OoOOOo, 0, Oo00oooo0ooO000OoOOOo.length);
if(Oo0o0O000oOOoOOOOOoOo == null)
{
byte O0oo00OOoOO0O0oOOO00o[] = Ooo0OoO000o0o0O00000o(OoO00OooOOo00o0Ooo0oo);
if(O0oo00OOoOO0O0oOOO00o != null)
Oo0o0O000oOOoOOOOOoOo
= defineClass(OoO00OooOOo00o0Ooo0oo, O0oo00OOoOO0O0oOOO00o, 0, O0oo00OOoOO0O0oOOO00o.length);
}
return Oo0o0O000oOOoOOOOOoOo;
}
。。。。。
public static void main(String O0OooOO0Ooo0o0O0OO000[])
{
try
{
new JFTServer(O0OooOO0Ooo0o0O0OO000);
}
catch(Exception Ooooo0oO00oo0o000oOOo)
{
System.out.println(Ooooo0oO00oo0o000oOOo.toString());
System.exit(0);
}
}
。。。。。
public static long O0o0O0OOOo000OOoooOOO(InputStream Oo0oOoOooOo0OO0O0O00O)//自校驗
{
。。。。。
}
private void Oo000OOo0ooO00o00oO0o()
{
。。。。。
Class O0oOOoOOO000o000O0Ooo = null;
try
{
O0oOOoOOO000o000O0Ooo = loadClass(OoooO0O000O0ooO0O0O0o,
true);//關鍵斷點
}
catch(ClassNotFoundException Ooooo0oO00oo0o000oOOo)
{
System.out.println(Ooooo0oO00oo0o000oOOo.toString());
System.exit(0);
}
try
{
Class O0OOOOOO000o0oO0oooO0[] = {
O00OO0000OOOoo00O0OoO.getClass()
};
Object O00O0oO0oO0o00OoOo0Oo[] =
{
O00OO0000OOOoo00O0OoO
};
Method OoO0Oo0oO0OoOOOooooO0 = O0oOOoOOO000o000O0Ooo.getMethod("main",
O0OOOOOO000o0oO0oooO0);
if(OoO0Oo0oO0OoOOOooooO0 == null)
{
System.out.println(Oo0oO0000O00OOOO00oO0.getString("main(String
argv[]) method can not be found in") + OoooO0O000O0ooO0O0O0o);
System.exit(0);
}
OoO0Oo0oO0OoOOOooooO0.invoke(null,
O00O0oO0oO0o00OoOo0Oo);
}
catch(IllegalAccessException Ooooo0oO00oo0o000oOOo)
{
System.out.println(Ooooo0oO00oo0o000oOOo.toString()
+ "Can not invoke the main(String) methos.");
System.exit(0);
}
catch(IllegalArgumentException Ooooo0oO00oo0o000oOOo)
{
System.out.println(Ooooo0oO00oo0o000oOOo.toString()
+ "Can not invoke the main(String) methos.");
System.exit(0);
}
catch(InvocationTargetException Ooooo0oO00oo0o000oOOo)
{
Ooooo0oO00oo0o000oOOo.printStackTrace();
System.out.println("Fire this
error to TDC, Sun(China)");
System.exit(0);
}
catch(Exception Ooooo0oO00oo0o000oOOo)
{
System.out.println(Ooooo0oO00oo0o000oOOo.toString()
+ Oo0oO0000O00OOOO00oO0.getString(" maybe password is wrong!"));
System.exit(0);
}
}
。。。。。。
}
}
如果用別的反編譯器可能程式碼會有些出入,不過沒多大關係。
因為經過了混淆處理,反編譯過來會有點難以理解,而且會有點小錯誤,沒關係,改掉就行了。我們把加密類解密後再儲存成檔案,接下來就把上面的findClass方法改成
protected Class findClass(String OoO00OooOOo00o0Ooo0oo)
throws ClassNotFoundException
{
Class Oo0o0O000oOOoOOOOOoOo = null;
byte Oo00oooo0ooO000OoOOOo[] = (byte[])O00oo0oO0o00O0o00O000.get(OoO00OooOOo00o0Ooo0oo);
if(Oo00oooo0ooO000OoOOOo != null && Oo00oooo0ooO000OoOOOo.length
!= 0) {
Oo0o0O000oOOoOOOOOoOo = defineClass(OoO00OooOOo00o0Ooo0oo,
Oo00oooo0ooO000OoOOOo, 0, Oo00oooo0ooO000OoOOOo.length);
//add by dayone
try {
FileOutputStream fileoutputstream
= new
FileOutputStream(String.valueOf(String.valueOf(OoO00OooOOo00o0Ooo0oo)).concat(".class"));
fileoutputstream.write(O0oo00OOoOO0O0oOOO00o);
fileoutputstream.close();
}
catch (IOException e) {
Class cls = findSystemClass(OoO00OooOOo00o0Ooo0oo);
return cls;
}
//
}
if(Oo0o0O000oOOoOOOOOoOo == null)
{
byte O0oo00OOoOO0O0oOOO00o[] = Ooo0OoO000o0o0O00000o(OoO00OooOOo00o0Ooo0oo);
if(O0oo00OOoOO0O0oOOO00o != null)
{
Oo0o0O000oOOoOOOOOoOo
= defineClass(OoO00OooOOo00o0Ooo0oo, O0oo00OOoOO0O0oOOO00o, 0, O0oo00OOoOO0O0oOOO00o.length);
//add by dayone
try {
FileOutputStream fileoutputstream
= new
FileOutputStream(String.valueOf(String.valueOf(OoO00OooOOo00o0Ooo0oo)).concat(".class"));
fileoutputstream.write(O0oo00OOoOO0O0oOOO00o);
fileoutputstream.close();
}
catch (IOException e) {
Class cls = findSystemClass(OoO00OooOOo00o0Ooo0oo);
return cls;
}
//
}
}
return Oo0o0O000oOOoOOOOOoOo;
}
當然別高興太早,編譯執行出現錯誤:
Error: there is something wrong with the class file net.xdevelop.JFTServer
原想遮蔽掉相關程式碼,但仔細研究後發現作者對JFTServer.class進行了校驗,改程式總會發生錯誤!(用二進位制編輯器開啟JFTServer.class,可以看出這個class已經被工具修改過了,有好多資訊都藏在裡面)那就來的偷樑換柱吧,把我們的JFTServer.java改名,其中的主類也改掉。把原來的JFTServer.class放到\net\xdevelop下,修改public
JFTServer(String O000O0OoO0O0OoOOOO00o[])方法中byte O00oOOOOO0OO0o000O0oO[] =
Ooo0OoO000o0o0O00000o(getClass().getName());為byte O00oOOOOO0OO0o000O0oO[]
=
Ooo0OoO000o0o0O00000o("net.xdevelop.JFTServer");再次執行就OK了。(要對其ip請求才能得到全部class檔案)把解密過的class檔案用小穎JAVA原始碼反編譯超級引摯V1.4
標準版批處理反編譯,沒辦法,因為發現一個個反編譯的話反編譯器要死掉。現在你就有了全部的原始碼了,我知道你接下來想幹什麼~
跟蹤程式執行,在private void Oo000OOo0ooO00o00oO0o()方法的O0oOOoOOO000o000O0Ooo = loadClass(OoooO0O000O0ooO0O0O0o,
true);處斷點可以看到程式呼叫了類Io0o0oO0O11I。也就是說我們找到真正的主類了。我們看其中的main方法:
public static void main(String l00OO0OlII0Il[])
{
System.out.println("JFT Server V4.0 (built
2003.6.30 10:00)");
System.out.println("JFT server starting ...");
if(!lIoo0O1IloOIO())
System.exit(-1);
if(!l00oOOl1Io0ll.l1IOOOo0lOO0l())//關鍵方法
{
System.out.println("JFT Server
V4.0(trial) Started.");
System.out.println("-------------------------NOTE-------------------------------------\r\nIt's
a unregistered
software.\r\n-----------------------------------------------------------------");
} else
{
System.out.println("JFT Server
V4.0 Started.");
}
try
{
lIo0o0oO0O11I l10oIll11o01O = new
lIo0o0oO0O11I();
l10oIll11o01O.start();
}
catch(Exception loIlOl01OlOIl)
{
System.out.println("JFT server
could not load successful: ".concat(String.valueOf(String.valueOf(loIlOl01OlOIl.getMessage()))));
}
}
於是來到關鍵類l00oOOl1Io0ll:
package l1OOoOIoo10OI.l0l110Il0lI11.l10O0o0o0Olo1.lOolI0ll0II00;
import java.io.PrintStream;
import java.security.MessageDigest;
import java.util.Date;
import l1OOoOIoo10OI.l0l110Il0lI11.l10O0o0o0Olo1.lO01IO1I1l1OO.l01oIl11OI0Ol;
public class l00oOOl1Io0ll
{
public static boolean l0l1l0l01l10l = false;
public static boolean loI00lIlI1I00 = false;
private l00oOOl1Io0ll()
{
}
public static void main(String l00OO0OlII0Il[])
{
String l1O1lIlol0o0I = l01l0O01O10OI("www.chinakingonline.com",
"standard");
System.out.print(l1O1lIlol0o0I);
}
public static String l0O0lIo11ooIo() //取得正確的註冊碼,做java版序號產生器可以直接拿來用。
{
String l1Ololl11Illl = l01oIl11OI0Ol.lIOlO00lIolOl;
//取得WEB_SITE的值 : 站點域名或IP地址
String l1O1lIlol0o0I = l01l0O01O10OI(l1Ololl11Illl,
l01oIl11OI0Ol.l10olIll0Il0o); // l01oIl11OI0Ol.l10olIll0Il0o為JFT_TYPE的值
return l1O1lIlol0o0I;
}
private static String l01l0O01O10OI(String l1Ololl11Illl, String
lO0oOo01o0OIo) //計算註冊碼
{
String llII0O0IO1oII = String.valueOf(String.valueOf((new
StringBuffer(String.valueOf(String.valueOf(l1Ololl11Illl)))).append(lO0oOo01o0OIo).append("4.0")));
String l1O1lIlol0o0I = "";
try
{
MessageDigest l1II1o00111Oo = MessageDigest.getInstance("SHA-1");
//採用SHA-1演算法
byte lO0101oOooolI[] = l1II1o00111Oo.digest(llII0O0IO1oII.getBytes());
for(int l1lolIlo0l01l = 0; l1lolIlo0l01l
< lO0101oOooolI.length; l1lolIlo0l01l++)
{
String lO010IIol010I
= Integer.toHexString(lO0101oOooolI[l1lolIlo0l01l]); //轉為16進位制
//取lO010IIol010I值的最後一位加到l1O1lIlol0o0I值的後面
l1O1lIlol0o0I = String.valueOf(l1O1lIlol0o0I)
+ String.valueOf(lO010IIol010I.substring(lO010IIol010I.length() - 1));
}
String s1 = l1O1lIlol0o0I;
return s1;
}
catch(Exception loIlOl01OlOIl)
{
System.out.println("Start JFTServer
LIC Error:".concat(String.valueOf(String.valueOf(loIlOl01OlOIl.getMessage()))));
}
String s = "";
return s;
}
public static boolean
l1IOOOo0lOO0l()
{
Date l001OI0O1l1OO;
String l1O1lIlol0o0I = l0O0lIo11ooIo();
if(l01oIl11OI0Ol.lI1llI0O1O0Io.equals(l1O1lIlol0o0I))
break MISSING_BLOCK_LABEL_97;
l001OI0O1l1OO = new Date();
if(l001OI0O1l1OO.getTime() <= 0xf758bb6c00L)
goto _L2; else goto _L1
_L1:
System.out.println("The software was expiered,
please download new version!");
System.out.println("Press Ctrl+C to end the
program!");
Exception exception;
try
{
Thread.sleep(0x186a0L);
}
finally
{
System.exit(-1);
}
goto _L2
exception;
_L2:
if(l01oIl11OI0Ol.lIooO0O0OIOol > 50)
l01oIl11OI0Ol.lIooO0O0OIOol = 50;
return false;
return true;
}
}
呵呵,終於完工了。總的來說此軟體採用了多種加密方式來保護,值得學習。
相關文章
- Oracle sqlprofile 偷樑換柱2012-05-29OracleSQL
- 偷樑換柱 - iOS實現UITextField+Limit2018-10-25iOSUIMIT
- 蘋果Mac修改圖示“偷樑換柱”的一種簡單方法2021-08-26蘋果Mac
- 網管軟體禁止網購木馬偷樑換柱2011-06-29
- 區塊鏈溯源防偽技術,杜絕“偷樑換柱”2020-12-07區塊鏈
- Java編譯與反編譯2021-03-20Java編譯
- 如何保護Java程式 防止Java反編譯2016-06-15Java編譯
- Java程式碼的編譯與反編譯那些事兒2019-05-09Java編譯
- java反編譯工具2021-08-13Java編譯
- Java反編譯器剖析2014-02-07Java編譯
- Java 反彙編、反編譯、volitale解讀2018-08-14Java編譯
- 通過反編譯深入理解Java String及intern2016-04-05編譯Java
- 小程式反編譯教程2020-11-15編譯
- c#程式反編譯2024-09-04C#編譯
- [java]javap命令列反編譯2013-04-15Java命令列編譯
- Java反編譯程式碼左側註釋批量清除2018-02-11Java編譯
- 如何反編譯微信小程式?2021-11-02編譯微信小程式
- 反編譯之JD-GUI程式碼邏輯分析2018-10-24編譯GUI
- JAVA反編譯技術研究心得2006-09-23Java編譯
- 反編譯之安裝Apktool2018-10-25編譯APK
- 安卓逆向之Luac解密反編譯2018-08-03安卓解密編譯
- Java反編譯工具使用對比,最好用的Java反編譯工具 --- JD-GUI、XJad2017-10-17Java編譯GUI
- Android反編譯:反編譯工具和方法2015-01-15Android編譯
- 一些防止java程式碼被反編譯的方法2017-09-21Java編譯
- ILSpy反編譯C#web程式2017-03-18編譯C#Web
- 7 款開源 Java 反編譯工具2014-09-26Java編譯
- 7款開源Java反編譯工具2014-08-31Java編譯
- python反編譯之位元組碼2019-05-19Python編譯
- pyhanlp 繁簡轉換之拼音轉換與字元正則化2019-06-28HanLP字元
- 反編譯apk2015-11-23編譯APK
- java 中文繁簡體轉換工具 opencc4j2021-09-09JavaOpencc4j
- Android反編譯和程式碼混淆2016-07-08Android編譯
- APK反編譯後程式碼分析(一)2014-03-06APK編譯
- Java Jar原始碼反編譯工具那家強2020-09-08JavaJAR原始碼編譯
- Android Apk反編譯得到Java原始碼2014-08-04AndroidAPK編譯Java原始碼
- 網站必備之簡繁切換功能實現2019-02-16網站
- Android Apk反編譯系列教程(一)如何反編譯APK2019-04-14AndroidAPK編譯
- 反編譯 iOS APP2018-01-03編譯iOSAPP