⑴ sublime text2 讓代碼恢復整齊
1.我們來講sublime自帶的、基本的代碼格式化功能——「reindent」。個人先建立了一個HTML頁面作為示例。多個元素的排列和縮進都被打亂。
8.總結,sublime本身只提供基本的縮進重置功能,不同語言的格式化可以使用不同的插件來實現。開源社區的生命力是無與倫比的,各種層出不窮的插件為我們的開發工作提供了諸多便利。
java從誕生以來,其基因就是開放精神,也正因此,其可以得到廣泛愛好者的支持和奉獻,最終很快發展壯大,以至於有今天之風光!但隨著java的應用領域越來越廣,特別是一些功能要發布到終端用戶手中(如Android開發的app),有時候,公司為了商業技術的保密考慮,不希望這裡面的一些核心代碼能夠被人破解(破解之後,甚至可以被簡單改改就發布出去,說嚴重點,就可能會擾亂公司的正常軟體的市場行為),這時候就要求這些java代碼不能夠被反編譯。
這里要先說一下反編譯的現象。因為java一直秉持著開放共享的理念,所以大家也都知道,我們一般共享一個自己寫的jar包時,同時會共享一個對應的source包。但這些依然與反編譯沒有什麼關系,但java的共享理念,不只是建議我們這樣做,而且它自己也在底層上「強迫」我們這么做!在java寫的.java文件後,使用javac編譯成class文件,在編譯的過程,不像C/C++或C#那樣編譯時進行加密或混淆,它是直接對其進行符號化、標記化的編譯處理,於是,也產生了一個逆向工程的問題:可以根據class文件反向解析成原來的java文件!這就是反編譯的由來。
但很多時候,有些公司出於如上述的原因考慮時,真的不希望自己寫的代碼被別人反編譯,尤其是那些收費的app或桌面軟體(甚至還有一些j2ee的wen項目)!這時候,防止反編譯就成了必然!但前面也說過了,因為開放理念的原因,class是可以被反編譯的,那現在有這樣的需求之後,有哪些方式可以做到防止反編譯呢?經過研究java源代碼並進行了一些技術實現(結果發現,以前都有人想到過,所以在對應章節的時候,我會貼出一些寫得比較細的文章,而我就簡單闡述一下,也算偷個懶吧),我總共整理出以下這幾種方式:
代碼混淆
這種方式的做法正如其名,是把代碼打亂,並摻入一些隨機或特殊的字元,讓代碼的可讀性大大降低,「曲線救國」似的達到所謂的加密。其實,其本質就是打亂代碼的順序、將各類符號(如類名、方法名、屬性名)進行隨機或亂命名,使其無意義,讓人讀代碼時很累,進而讓人乍一看,以為這些代碼是加過密的!
由其實現方式上可知,其實現原理只是擾亂正常的代碼可讀性,並不是真正的加密,如果一個人的耐心很好,依然可以理出整個程序在做什麼,更何況,一個應用中,其核心代碼才是人們想去了解的,所以大大縮小了代碼閱讀的范圍!
當然,這種方式的存在,而且還比較流行,其原因在於,基本能防範一些技術人員進行反編譯(比如說我,讓我破解一個混淆的代碼,我寧願自己重寫一個了)!而且其實現較為簡單,對項目的代碼又無開發上的侵入性。目前業界也有較多這類工具,有商用的,也有免費的,目前比較流行的免費的是:proguard(我現象臨時用的就是這個)。
上面說了,這種方式其實並不是真正加密代碼,其實代碼還是能夠被人反編譯(有人可能說,使用proguard中的optimize選項,可以從位元組流層面更改代碼,甚至可以讓JD這些反編譯軟體可以無法得到內容。說得有點道理,但有兩個問題:1、使用optimize對JDK及環境要求較高,容易造成混淆後的代碼無法正常運行;2、這種方式其實還是混淆,JD反編譯有點問題,可以有更強悍的工具,矛盾哲學在哪兒都是存在的^_^)。那如何能做到我的class代碼無法被人反編譯呢?那就需要我們下面的「加密class」!
加密class
在說加密class之前,我們要先了解一些java的基本概念,如:ClassLoader。做java的人已經或者以後會知道,java程序的運行,是類中的邏輯在JVM中運行,而類又是怎麼載入到JVM中的呢(JVM內幕之類的,不在本文中闡述,所以點到為止)?答案是:ClassLoader。JVM在啟動時是如何初始化整個環境的,有哪些ClassLoader及作用是什麼,大家可以自己問度娘,也不在本文中討論。
讓我們從最常見的代碼開始,揭開一下ClassLoader的一點點面紗!看下面的代碼:
Java代碼
publicclassDemo{
publicstaticvoidmain(String[]args){
System.out.println(「helloworld!」);
}
}
上面這段代碼,大家都認識。但我要問的是:如果我們使用javac對其進行編譯,然後使用java使其運行(為什麼不在Eclipse中使用Runas功能呢?因為Eclipse幫我們封閉,從而簡化了太多東西,使我們忽略了太多的底層細節,只有從原始的操作上,我們才能看到本質),那麼,它是怎麼載入到JVM中的?答案是:通過AppClassLoader載入的(相關知識點可以參考:http://hxraid.iteye.com/blog/747625)!如果不相信的話,可以輸出一下System.out.println(Thread.currentThrea().getContextLoader());看看。
那又有一個新的問題產生了:ClassLoader又是怎樣載入class的呢?其實,AppClassLoader繼承自java.lang.ClassLoader類,所以,基本操作都在這個類裡面,讓我們直接看下面這段核心代碼吧:
看到這里,已經沒有必要再往下面看了(再往下就是native方法了,這是一個重大伏筆哦),我們要做的手腳就在這里!
手腳怎麼做呢?很簡單,上面的代碼邏輯告訴我們,ClassLoader只是拿到class文件中的內容byte[],然後交給JVM初始化!於是我們的邏輯就簡單了:只要在交給JVM時是正確的class文件就行了,在這之前是什麼樣子無所謂!所以,我們的加密的整個邏輯就是:
在編譯代碼時(如使用ant或maven),使用插件將代碼進行加密(加密方式自己選),將class文件裡面的內容讀取成byte[],然後進行加密後再寫回到class文件(這時候class文件裡面的內容不是標準的class,無法被反編譯了)
在啟動項目代碼時,指定使用我們自定義的ClassLoader就行了,而自定義的部分,主要就是在這里做解密工作!
如此,搞定!以上的做法比較完整的闡述,可以仔細閱讀一下這篇文章:https://www.ddtsoft.com/#developerworks/cn/java/l-secureclass/文章中的介紹。
通過這個方法貌似可以解決代碼反編譯的問題了!錯!這里有一個巨大的坑!因為我們自定義的ClassLoader是不能加密的,要不然JVM不認識,就全歇菜了!如果我來反編譯,呵呵,我只要反編譯一下這個自定義的ClassLoader,然後把裡面解密後的內容寫到指定的文件中保存下來,再把這個加了邏輯的自定義ClassLoader放回去運行,你猜結果會怎樣?沒錯,你會想死!因為你好不容易想出來的加密演算法,結果人家根本不需要破解,直接就繞過去了!
現在,讓我們總結一下這個方法的優缺點:實現方式簡單有效,同時對代碼幾乎沒有侵入性,不影響正常開發與發布。缺點也很明顯,就是很容易被人破解!
當然啦,關於缺點問題,你也可以這么干:先對所有代碼進行混淆、再進行加密,保證:1、不容易找到我們自定義的那個ClassLoader;2、就算找到了,破解了,代碼可讀性還是很差,讓你看得吐血!(有一篇文章,我覺得寫得不錯,大家可以看一看:http://www.scjgcj.com/#blog/851544)
嗯,我覺得這個方法很好,我自己也差點被這個想法感動了,但是,作為一個嚴謹的程序員,我真的不願意留下一個隱患在這里!所以,我繼續思索!
高級加密class
前面我們說過有個伏筆來著,還記得吧?沒錯,就是那個native!native定義的方法是什麼方法?就是我們傳說中的JNI調用!前面介紹過的有一篇文章中提到過,其實jvm的真實身份並不是java,而是c++寫的jvm.dll(windows版本下),java與dll文件的調用就是通過JNI實現的!於是,我們就可以這樣想:JNI可以調用第三方語言的類庫,那麼,我們可不可以把解密與裝載使用第三方語言寫(如C++,因為它們生成的庫是不好反編譯的),這樣它可以把解密出來的class內容直接調jvm.dll的載入介面進行初始化成class,再返回給我們的ClassLoader?這樣,我們自定義的ClassLoader只要使用JNI調用這個第三方語言寫的組件,整個解密過程,都在黑盒中進行,別人就無從破解了!
嗯,這個方法真的很不錯的!但也有兩個小問題:1.使用第三方語言寫,得會第三方語言,我說的會,是指很溜!2.對於不同的操作系統,甚至同一操作系統不同的版本,都可能要有差異化的代碼生成對應環境下的組件(如window下是exe,linux是so等)!如果你不在乎這兩個問題,我覺得,這個方式真的挺不錯的。但對於我來說,我的信條是,越復雜的方式越容易出錯!我個人比較崇尚簡潔的美,所以,這個方法我不會輕易使用!
對了,如果大家覺得這個方法還算可行的話,可以推薦一個我無意中看到的東西給大家看看(我都沒有用過的):jinstall,
更改JVM
看到這個標題,我想你可能會震驚。是的,你沒看錯,做為一個程序員,是應該要具有懷疑一切、敢想敢做的信念。如果你有意留心的話,你會發現JVM版本在業界其實也有好幾個版本的,如:Sun公司的、IBM的、Apache的、Google的……
所以,不要阻礙自己的想像力,現在沒有這個能力,並不代表不可能。所以,我想到,如果我把jvm改了,在裡面對載入的類進行解密,那不就可以了嗎?我在設計構思過程中,突然發現:人老了就是容易糊塗!前面使用第三方語言實現解密的兩個問題,正好也是更改JVM要面對的兩個問題,而且還有一個更大的問題:這個JVM就得跟著這個項目到處走啊!
⑶ 為什麼把正確的代碼復制到編譯器中錯誤百出
一般都是編譯器版本的問題,可以根據錯誤對編譯器進行調整或者對代碼進行修改,都不是啥大問題。
⑷ C#如何防止被別人反編譯
C#
編寫的代碼通過VS編譯器生成
dll
或
exe
,很容易被一些反編譯工具查看到源碼或對源碼進行修改。
為防止代碼被反編譯或被篡改,我們可以進行一定的防範措施。但不能杜絕,因為DotNet編寫代碼運行必須編譯成IL
中間語言,IL是很規則,同時也很好反編譯。
反編譯防範措施:
設置項目代碼反匯編屬性
混淆
方法一:防止
Ildasm.exe(MSIL
反匯編程序)
反匯編程序集
方法很簡單在項目文件AssemblyInfo.cs中增加SuppressIldasm屬性。
當項目中增加SuppressIldasm屬性後在使用ildasm.exe反編譯代碼,會提示:"受保護的模塊
--
無法進行反匯編"
ildasm.exe
讀取項目中包含
SuppressIldasm
屬性就不對此程序集進行反編譯。但ILSyp,Reflector等反編譯工具針對程序集設置SuppressIldasm屬性置之不理,一樣可以反編譯源碼。
缺點:
可見SuppressIldasm
屬性只針對ildasm.exe工具起效果,同時也能刪除ildasm.exe工具的此項限制。參考:《去掉ILDasm的SuppressIldasmAttribute限制》
方法二:混淆
混淆原理:將VS編譯出的文件(exe
或
dll)通過ildasm對文件進行重命名,字元串加密,移動等方式將原始代碼打亂。這種方式比較常見。
VS2013
自帶混淆工具:工具-->PreEmptive
Dotfuscator
and
Analytics
但VS2013自帶Dotfuscator
5.5
需購買激活才能使用全部功能。目前網路提供
DotfuscatorPro
4.9
破解版版本下載。
打開
DotfuscatorPro
4.9
主界面
Settings->Global
Options
全局配置
常用功能配置:Disable
String
Encryption=NO
啟用字元串加密
選擇需混淆C#編譯代碼(dll
或
exe)
其中Library不要勾選,否則有些類、變數等等不會混淆;
Rename
重命名配置
常用功能配置:
勾選
=
use
enhanced
overload
inction
使用增強模式
重命名方案
Renaming
Scheme
=
Unprintable
(不可列印字元,即亂碼),也可以選擇其他如小寫字母、大寫字元、數字的方式。
String
Encryption
字元串加密
勾選需要加密字元串文件(exe
或
dll)
可根據各自需求可進行其他相關配置。(如:control
flow,Output,Setting
->Build
Settings,Settings
-->
Project
Properties等)
最後生成混淆文件
Build
Project。
Build
Project
生成混淆項目錯誤:
Could
not
find
a
compatible
version
of
ildasm
to
run
on
assembly
C:Users***.exe.??This
assembly
was
originally
built
with
.NET
Framework
v4.0.30319.
Build
Error.
處理方法:
ILASM_v4.0.30319
=
C:WindowsMicrosoft.NETFrameworkv4.0.30319ilasm.exe
ILDASM_v4.0.30319
=
C:Program
Files
(x86)Microsoft
SDKsWindowsv8.1AinNETFX
4.5.1
Toolsildasm.exe
[安裝VS版本不同對應目錄會有所變化]
混淆代碼對比
未使用混淆工具,反編譯出的源碼:
使用混淆工具,反編譯出的源碼:
效果很明顯,很難看出反編譯代碼所寫的真正邏輯。
缺點:
C#代碼通過混淆工具生成後,增加了很多轉換過程。這使得反編譯工具無法很直觀看到源碼真正邏輯。但源碼代碼過多轉換會使軟體本身運行效率降低,甚至會出現報錯情況。
⑸ pascal語言編譯器打開後的亂碼怎麼弄
右鍵圖標,點擊屬性,選擇上面一欄的「選項」,然後將當前代碼頁改成美國,就可以了。
⑹ Microsoft VBScript 編譯器錯誤 錯誤 '800a0408' 如何解決
800a0408表示無效的字元
錯誤原因:空格中可能包含中文的空格,代碼中間的那些空格中可能包含中文的空格,雖然都是空格,看起來都差不多,但英文的語言是半形的英文字元,而中文的字元是全形的。
解決辦法
可以把出錯的那行的空格都刪除,用tab鍵或是重新用半形空格來替代,切換英文半形認識如下:
1、在搜狗輸入法的英文狀態下,「英」字後邊的那個符號,為全形半形符號。
⑺ 編譯器錯誤怎麼解決
1、分析原因,這樣的錯誤出現一般是由於伺服器拒絕了某一項請求,常見的是寫入,所以問題在有表單輸入的網頁中更容易出現。
⑻ 編譯器生成的匯編語句執行順序為什麼與C代碼順序不同
不影響語義的前提下編譯器可以任意重排代碼順序;
在亂序執行(Out-of-Order)的CPU里,機器碼的執行也可以不按照你在「匯編」層面上看到的順序執行,只要不影響語義。
所以說這些中間步驟的順序,作為底層細節平時不需要那麼在意——它們多半跟原始源碼的順序是不一樣的。
現代優化編譯器優化的思路之一是「基於依賴的優化」(dependence-based optimization)。題主引用的CSAPP的例子:
int arith(int x, int y, int z) {
int t1 = x + y;
int t2 = z * 48;
int t3 = t1 & 0xFFFF;
int t4 = t2 * t3;
return t4;
}
所有涉及運算的值都是局部標量變數(local scalar variable),這是最便於編譯器做分析的情況,所有依賴都可以顯式分析。
由於整個函數沒有分支,這里也不需要討論控制依賴(control dependence),只要討論數據依賴(data dependence)就好。
把數據依賴圖畫出來是個DAG(這里正好是棵樹,特例了):
x y z 48
\ / \ /
t1 0xFFFF t2
\ / /
t3 /
\ /
t4
優化必須要滿足的約束是:每個節點求值之前,其子節點(依賴的數據源)必須要先求了值。
顯然,t1和t2之間沒有依賴關系,它們的相對求值順序怎樣重排都沒關系。
有本我很喜歡的書,裡面講的是各種基於依賴的優化:Optimizing Compilers for Modern Architectures - A Dependence-based Approach
以上是理論部分。
================================================================
下面來看例子。
我們可以用一個實際編譯器來看看CSAPP的例子編譯出來的結果:
.text
# -- Begin arith
.p2align 4,,15
.globl arith
.type arith, @function
arith:
.p2align 4,,7
/*.L0:*/ /* Block BB[54:2] preds: none, freq: 1.000 */
movl 8(%esp), %edx /* ia32_Load T[139:10] -:1:22 */
addl 4(%esp), %edx /* ia32_Add Iu[141:12] -:2:14 */
movzwl %dx, %edx /* ia32_Conv_I2I Iu[142:13] -:4:15 */
imull 12(%esp), %edx /* ia32_IMul Iu[143:14] -:5:15 */
leal (%edx,%edx,2), %eax /* ia32_Lea Iu[144:15] -:5:15 */
shll $0x4, %eax /* ia32_Shl Iu[146:17] -:5:15 */
ret /* ia32_Return X[152:23] -:6:3 */
.size arith, .-arith
# -- End arith
這里用的是libFirm。可見它跟CSAPP書里所說的匯編的順序又有所不同。這也是完全合理的。
這個編譯結果的順序是:
edx = y;
edx += x;
edx = zeroextend dx; // edx = edx & 0xFFFF
edx *= z;
eax = edx * 3;
eax <<= 4; // eax = eax * 16
也是完全符合依賴關系的約束的一種順序。
之所以用libFirm舉例是因為它的中間表示(Intermediate Representation)是一種程序依賴圖(Program Dependence Graph),可以很方便的看出控制與數據依賴。把CSAPP那裡例子對應的libFirm IR畫出來,是這個樣子的:
(這張圖跟我前面畫的數據依賴圖正好是左右翻轉的,不過意思一樣。(這張圖跟我前面畫的數據依賴圖正好是左右翻轉的,不過意思一樣。
Arg 0、1、2分別代表x、y、z。白色方塊是普通數據節點,黃色方塊是常量節點,藍色方塊是內存相關節點,紅色方塊是控制流節點,粉紅色方塊是特殊的開始/結束節點。)
某版LLVM生成的代碼:
; MoleID = '/tmp/webcompile/_16355_0.bc'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-ellcc-linux"
; Function Attrs: nounwind readnone
define i32 @arith(i32 %x, i32 %y, i32 %z) #0 {
entry:
%add = add nsw i32 %y, %x
%mul = mul nsw i32 %z, 48
%and = and i32 %add, 65535
%mul1 = mul nsw i32 %mul, %and
ret i32 %mul1
}
attributes #0 = { nounwind readnone "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
!llvm.ident = !{!0}
!0 = !{!"ecc 0.1.10 based on clang version 3.7.0 (trunk) (based on LLVM 3.7.0svn)"}
最終生成的x86匯編:
.text
.file "/tmp/webcompile/_15964_0.c"
.globl arith
.align 16, 0x90
.type arith,@function
arith: # @arith
# BB#0: # %entry
movl 8(%esp), %eax
addl 4(%esp), %eax
movzwl %ax, %eax
imull 12(%esp), %eax
shll $4, %eax
leal (%eax,%eax,2), %eax
retl
.Ltmp0:
.size arith, .Ltmp0-arith
.ident "ecc 0.1.10 based on clang version 3.7.0 (trunk) (based on LLVM 3.7.0svn)"
.section ".note.GNU-stack","",@progbits
GCC 4.9.2 x86-64:
arith(int, int, int):
leal (%rdx,%rdx,2), %eax
addl %edi, %esi
movzwl %si, %esi
sall $4, %eax
imull %esi, %eax
ret
Zing VM Server Compiler x86-64:
# edi: x
# esi: y
# edx: z
movl %edx, %eax
shll $0x4, %eax
leal (%rsi, %rdi, 1), %ecx
shll $0x5, %edx
addl %edx, $eax
movzwl %ecx, %edx
imull %edx, %eax
⑼ Flash編譯器錯誤 動作代碼錯誤 急急急急急急
需要整段代碼,整體這個文件的代碼,有時候不一定是這個行的錯誤。這種情況一般都是書寫錯誤造成的。