首先先說說as的abc文件
從下面的am2框架圖可以看出abc文件所處的位置
abc文件
abc文件就是flash player可以直接解釋執行的的字節碼,該文件中的內容會直接嵌入到swf文件的doABC標簽下。源碼的asc包就是處理abc格式的。通常在編譯AS項目時,as3腳本文件都會被編譯成abc文件然后再生成doABC標簽。
手工編譯as3到abc文件
在flash sdk的lib目錄下,有個asc.jar,該文件就是用來生成abc文件的java程序,機器上要安裝java運行時。
* 新建一個文件Hello.as,並寫上一行代碼 print("Hello");
* 在控制台中輸入cd C:\Program Files\Adobe\Adobe Flash Builder 4\sdks\4.0.0\lib
* 在控制台中輸入java -jar asc.jar Hello.as,
編譯成功,輸出Hello.abc, 79 bytes written
察看Hello.as文件所在目錄會發現新生成一個Hello.abc文件。
繼續上面,把Hello.as文件改為一個class看看;
* 把的代碼改成
package {
import flash.display.Sprite;
public class Hello extends Sprite {
public function Hello() {
trace("Hello");
}
}
}
* 編譯,出現[Compiler] Error #1017: The definition of base class Sprite was not found.提示,這是由於缺少Sprite類的定義
* 導入as基本庫:在asc源碼包下有個abc文件,里面有builtin.abc,playerglobal.abc,toplevel.abc三個文件,他們就是flash的基本庫。asc的命令行參數可以直接用java -jar asc.jar來查看。
重新輸入命令
java -jar asc.jar -import E:\work\sdksrc\modules\asc\abc\builtin.abc -import E:\work\sdksrc\modules\asc\abc\playerglobal.abc Hello.as
可以看到編譯成功。
ABC文件的格式
abcFile
{
u16 minor_version
u16 major_version
cpool_info constant_pool
u30 method_count
method_info method[method_count]
u30 metadata_count
metadata_info metadata[metadata_count]
u30 class_count
instance_info instance[class_count]
class_info class[class_count]
u30 script_count
script_info script[script_count]
u30 method_body_count
method_body_info method_body[method_body_count]
}
常量池
cpool_info
{
u30 int_count
s32 integer[int_count]
u30 uint_count
u32 uinteger[uint_count]
u30 double_count
d64 double[double_count]
u30 string_count
string_info string[string_count]
u30 namespace_count
namespace_info namespace[namespace_count]
u30 ns_set_count
ns_set_info ns_set[ns_set_count]
u30 multiname_count
multiname_info multiname[multiname_count]
}
在abc文件(參考“flash sdk開源相關的一些東西”)中,所有的字符串值都會保存到常量池的字符常量string_info string[string_count] 段中,因此要混淆代碼,只要把該段中的字符串值進行混淆就可以了。
但flash中的api中的類和方法以及代碼中使用的字符串常量,還有導出類(SymbolClass標簽中的)等是不能混淆的。實際上,需要混淆的只是自己定義的類和類的屬性、方法。用戶自己定義的類及屬性方法可以在
u30 class_count
instance_info instance[class_count]
class_info class[class_count]
段中找到。class_count 是所有用戶定義的類的總數。段的定義結構如下:
instance_info
{
u30 name
u30 super_name
u8 flags
u30 protectedNs
u30 intrf_count
u30 interface[intrf_count]
u30 iinit
u30 trait_count
traits_info trait[trait_count]
}
class_info
{
u30 cinit
u30 trait_count
traits_info traits[trait_count]
}
另一個問題,在abc文件中,所有相同的字符串都會保存為同一個字符串值常量,當類或方法名根代碼中的字符串相同時,則不能混淆。如下例子:
class Test {
public function Test() {
var str:String = "Test";
trace(str);
}
}
這時候,如果將Test類名混淆為a,那么str的值也會變為a,這樣會改變str的值,因此混淆時還需要排出跟代碼中字符串相同的類、方法或屬性。
想要找出代碼中使用的字符串,需要分析方法體內容,即
u30 method_body_count
method_body_info method_body[method_body_count]
段內容。方法體定義如下:
method_body_info
{
u30 method
u30 max_stack
u30 local_count
u30 init_scope_depth
u30 max_scope_depth
u30 code_length
u8 code[code_length]
u30 exception_count
exception_info exception[exception_count]
u30 trait_count
traits_info trait[trait_count]
}
方法體的
u30 code_length
u8 code[code_length]
段記錄了方法中的所有操作,只要找到其中的OP_pushstring(操作碼0x2C)即為字符串賦值操作,根據該操作碼后的字符串索引即可在字符串池中找到該字符串,將此字符串加入到排除列表即可。