2012年5月28日 星期一

[iOS] 使用 absinthe-win-2.0.2 來 Jailbreak iPad 1 iOS 5.1.1 @ VirtualBox


圖:http://greenpois0n.com/


這年頭 Jailbreak 越來越方便 XD 最重要的是漸漸可以用 VirtualBox 完工了!甚至 JB 程式不只 WindowsMac 版,還推出了 Linux 版。真是有夠威。建議要使用的人還是連去官網下載吧(還用Google Docs哩)!以免不小心抓到木馬。


jailbreak jailbreak_done


此次環境:


Guest OS:Windows XP SP3
Host OS:Windows 7 64Bit
Target:iPad 1 WiFi 版 with iOS 5.1.1 (9B206)


首先把 iPad 1 升到 iOS 5.1.1,再來使用 VirtualBox 來進行 JB,在 C:\ 點選剛下載好的 absinthe-win-2.0.2.exe 後自動解壓縮一個目錄,接著再進去點選該執行檔即可。(如果 iPad 1 已在 JB 狀態下了,無法透過網路升級時,可直接下載 iPad1,1_5.1.1_9B206_Restore.ipsw 並透過 iTunes 回復方式來升級)


如果使用上執行進度卡住時,可以試試把 VirtualBox 重新接上 iPad 看看,畢竟 iPad 裝置有 3 個 status,每一個狀態被偵測的項目是不一樣的,如 Apple Inc. Apple Mobile Device (Recovery Mode)、Apple Inc. Apple Mobile Device (DFU Mode)、Apple Inc. iPad [0001] 等等或是把 iPad 各個狀態都在 VirtualBox 設定好 USB 自動偵測使用應該也能解掉,此外也要留意 Host 上頭若有裝 iTunes 程式,要小心這些程式佔用資源,將導致 VirtualBox 無法取用 iPad 喔,解法大概就用 taskmgr 去把 AppleMobileDeviceService.exe 、iPosService.exe 等相關的關掉在試看看吧


2012年5月26日 星期六

[LLVM] LLVM、Clang、Clang Plugin、Clang Rewriter 筆記 @ Ubuntu 64bit

Source: http://en.wikipedia.org/wiki/LLVM
圖片來源:http://llvm.org/Logo.html


第一次看到 Open source project 覺得 LOGO 很殺 XD 這也代表 LLVM 真的有某個層度的威力!LLVM 全名為 Low Level Virtual Machine,翻譯為底層虛擬機器,並且從 wiki 介紹可以略知一二,就是透過虛擬技術來作最佳化。



  • http://llvm.org/

  • http://en.wikipedia.org/wiki/LLVM


    • LLVM (formerly Low Level Virtual Machine) is a compiler infrastructure written in C++ that is designed for compile-time, link-time, run-time, and "idle-time" optimization of programs written in arbitrary programming languages.


  • http://zh.wikipedia.org/zh-tw/LLVM


    • LLVM ,命名最早源自於底層虛擬機器(Low Level Virtual Machine)的縮寫[1]。它是一個編譯器的基礎建設,以C++寫成。它是為了任意一種程式語言寫成的程式,利用虛擬技術,創造出編譯時期,鏈結時期,執行時期以及「閒置時期」的最佳化。



談論到虛擬機器,對資訊領域最親近的程式語言是 Java,以及 Java bytecode、Java Virtual Machine (JVM) 和跨平台的關係。將 Java 程式碼 (.java) 編譯成 bytecode (.class) 後,透過 JVM 可執行結果,加上多種平台都有 JVM (Windows/Linux/Mac),提供開發者只需撰寫一份程式碼、僅需編譯一次,接著就可以拿著編譯完的結果到各類有支援 JVM 的平台執行,成果就達成了跨平台。若粗淺地看 LLVM 的話,也有類似的關係,只是這時架構稍微調整成:


N 種程式語言 (front ends) > 產生 LLVM Bitcode > 產生 M 個程式執行環境 (back ends)


而 LLVM 能做的事不止於此,還可進行程式效能最佳化處理等等。


首先提一下安裝 LLVM 的部分好了,參考官方文件的介紹,在此選擇 Ubuntu 64bit 環境:


$ uname -a
Linux 2.6.32-38-server #83-Ubuntu SMP Wed Jan 4 11:26:59 UTC 2012 x86_64 GNU/Linux
$ dmesg | grep -i cpu
Intel(R) Xeon(R) CPU E5420 @ 2.50GHz

下載程式碼:


$ cd ~/ && svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
$ cd ~/llvm/tools/ && svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
$ cd ~/llvm/projects && svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
$ cd ~/llvm/projects && svn co http://llvm.org/svn/llvm-project/test-suite/trunk test-suite

採用官方編譯方式:


$ cd ~/ && mkdir -p build out && cd ~/build && ../llvm/configure --prefix=$HOME/out
$ time make -j8
real 9m55.952s
user 47m7.270s
sys 5m49.610s

採用 cmake 編譯方式:


$ sudo apt-get install cmake
$ cd ~/ && mkdir -p build out && cd ~/build && cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/out ../llvm
$ time make -j8
real 5m39.994s
user 37m23.290s
sys 4m27.790s

原先是某次用 configure 編譯會過不了(trunk版本常碰到的現象),就嘗試用 CMAKE ,結果一用發現編得更快,從此我就都用 CMAKE 了 XDDD (或許有少編啥東西 :P 但不影響我研究,就沒計較了) 須留意編譯 Clang plugin 的部分,如果 llvm 採用 configure 編法,那只需切換到 clang plugin project 中執行 make 即可,其他細節可參考 PrintFunctionNames 裡的 README,如果採用 CMAKE 編法,記得要跑去 CMake 產生得相對目錄結構中,執行 make 才會編出來,並且編出來的位置是擺在在 lib 中(此例是~/build/lib)。


研究一下 clang 的用處好了,最直觀的用途是像 gcc 的編譯器功能(並非全部功能都支援, 這跟LLVM架構有關),把 source code 編譯成執行檔,而 compiler 有很多種,例如 one-pass 跟 multi-pass compiler,我想 LLVM 架構應該算 multi-pass 的,由 clang 作為 front end 的部份,將程式碼編譯成 LLVM Bitcode,接著在經由 LLVM 架構,搭配 back ends 端產出各種平台的 native code。而 clang 的功能不只於此,參考 Google 發表的相關文章 C++ at Google: Here Be Dragons,可以透過 clang 來處理一些錯誤偵錯,例如 bool *charge_acct 變數,操作上不小心弄成 charge_acct = false 的問題(正確使用應該是 charge_acct = NULL 或 *charge_acct = false),更多介紹請參考 Chromium Style Checker Errors。簡言之,透過 clang 可以幫忙掃 source code 找一些容易忽略的錯誤,並且輸出人性化的訊息。相關產品: Clang Static Analyzer


由於 Clang 可以分析 source code,那就存在很多玩法,且架構上提供 clang plugin 用法。範例程式:clang/examples/PrintFunctionNames/PrintFunctionNames.cpp,翻閱一下,可以看到一些關鍵字:PluginASTActionASTConsumer,其中 AST 在 Compiler 界全名為 Abstract Syntax Tree,就是把程式碼建立一個 tree 結構,方便分析。


至於寫一個 Clang Plugin 要做的事:(可從範例程式 PrintFunctionNames 複製一份再來修改)



  1. 撰寫 PluginASTAction


    • 關於 PluginASTAction 架構可參考 http://clang.llvm.org/doxygen/classclang_1_1PluginASTAction.html, 簡言之,包括 CreateASTConsumer 與 ParseArgs,其中 ParseArgs 可透過參數來初始化 plugin 操作環境或是區分要執行那個動作,而 CreateASTConsumer 則是核心項目,也就是依工作目的建立自己的 ASTConsumer。


  2. 撰寫 ASTConsumer


  3. 註冊操作時使用的名稱


    • 此 PrintFunctionNames 為 print-fns


  4. 編譯產生 xxx.so 或在 Mac 為 xxx.dylib 檔


    • 此 PrintFunctionNames  為 PrintFunctionNames.so 或 libPrintFunctionNames.so


  5. 操作使用 clang -cc1 -load /path/xxx.so -plugin YourPluginName YourInputFile 或 clang -cc1 -load /path/xxx.so -plugin YourPluginName -plugin-arg-YourPluginName YourArgs YourInputFile


    • clang -cc1 -load /path/PrintFunctionNames.so -plugin print-fns some-input-file.c

    • clang -cc1 -load /path/PrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c



在 PrintFunctionNames 例子來說,在 PluginASTAction::ParseArgs 有一個簡易判斷參數的架構;在 ASTConsumer 裡頭,使用 HandleTopLevelDecl 功能,用來輸出程式碼內的 top level function name。因此,若要寫 Clang Plugin 的話,可以從 PrintFunctionNames 的架構修改。接著更複雜的應用就是 source-to-source translation,可用 Google 搜尋 clang source to source translation 或 clang rewriter 看看,最經典的例子是 lib/Rewrite/RewriteObjC.cpp


使用 clang rewriter 進行 source to source translation,將 ObjC 程式碼轉成 C 語言:


$ sudo apt-get install llvm clang g++
$ vim Hello.m
#import
int main( int argc, const char *argv[] ) {
printf( "hello world\n" );
return 0;
}
$ clang -rewrite-objc Hello.m
$ cat Hello.cpp
#ifndef __OBJC2__
#define __OBJC2__
#endif
struct objc_selector; struct objc_class;
struct __rw_objc_super {
struct objc_object *object;
struct objc_object *superClass;
__rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {}
};
#ifndef _REWRITER_typedef_Protocol
typedef struct objc_object Protocol;
#define _REWRITER_typedef_Protocol
#endif
#define __OBJC_RW_DLLIMPORT extern
__OBJC_RW_DLLIMPORT void objc_msgSend(void);
__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);
__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);
__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);
__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);
__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass(const char *);
__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass(struct objc_class *);
__OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass(const char *);
__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);
__OBJC_RW_DLLIMPORT void objc_sync_enter( struct objc_object *);
__OBJC_RW_DLLIMPORT void objc_sync_exit( struct objc_object *);
__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);
#ifndef __FASTENUMERATIONSTATE
struct __objcFastEnumerationState {
unsigned long state;
void **itemsPtr;
unsigned long *mutationsPtr;
unsigned long extra[5];
};
__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);
#define __FASTENUMERATIONSTATE
#endif
#ifndef __NSCONSTANTSTRINGIMPL
struct __NSConstantStringImpl {
int *isa;
int flags;
char *str;
long length;
};
#ifdef CF_EXPORT_CONSTANT_STRING
extern "C" __declspec(dllexport) int __CFConstantStringClassReference[];
#else
__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];
#endif
#define __NSCONSTANTSTRINGIMPL
#endif
#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
// Runtime copy/destroy helper functions (from Block_private.h)
#ifdef __OBJC_EXPORT_BLOCKS
extern "C" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);
extern "C" __declspec(dllexport) void _Block_object_dispose(const void *, const int);
extern "C" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];
extern "C" __declspec(dllexport) void *_NSConcreteStackBlock[32];
#else
__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);
__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);
__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];
__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];
#endif
#endif
#define __block
#define __weak

#include
struct __NSContainer_literal {
void * *arr;
__NSContainer_literal (unsigned int count, ...) {
va_list marker;
va_start(marker, count);
arr = new void *[count];
for (unsigned i = 0; i < count; i++)
arr[i] = va_arg(marker, void *);
va_end( marker );
};
~__NSContainer_literal() {
delete[] arr;
}
};
extern "C" __declspec(dllimport) void * objc_autoreleasePoolPush(void);
extern "C" __declspec(dllimport) void objc_autoreleasePoolPop(void *);

struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};

#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)
#include

int main( int argc, const char *argv[] ) {
printf( "hello world\n" );
return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

$ g++ -o Hello Hello.cpp
$ ./Hello
hello world

至於如何寫 Clang Rewriter 呢,就是直接參考 lib/Rewrite/RewriteObjC.cpp 這隻幾千行的程式碼吧!裡頭已經有豐富的資料可以參考,此例主要的有兩個 class :


class RewriteObjC : public ASTConsumer
class RewriteObjCFragileABI : public RewriteObjC


程式主體是 RewriteObjC,但使用時是用 RewriteObjCFragileABI:


ASTConsumer *clang::CreateObjCRewriter(const std::string& InFile, raw_ostream* OS, DiagnosticsEngine &Diags, const LangOptions &LOpts, bool SilenceRewriteMacroWarning) {
return new RewriteObjCFragileABI(InFile, OS, Diags, LOpts, SilenceRewriteMacroWarning);
}

一開始的程式進入點在 ASTConsumer constructor,隨後還有 virtual void Initialize(ASTContext &context),接著就跟 clang plugin example PrintFunctionNames 流程差不多,可以追 ASTConsumer 的 public functions 瞧瞧,如 virtual bool HandleTopLevelDecl(DeclGroupRef D) 等。


因此,撰寫的主體大概擺在 bool HandleTopLevelDecl(DeclGroupRef D) 裡頭,此例在 RewriteObjC 的宣告及 HandleTopLevelDecl 定義處:


// Top Level Driver code.
virtual bool HandleTopLevelDecl(DeclGroupRef D) {
for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I) {
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*I)) {
if (!Class->isThisDeclarationADefinition()) {
RewriteForwardClassDecl(D);
break;
}
}

if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*I)) {
if (!Proto->isThisDeclarationADefinition()) {
RewriteForwardProtocolDecl(D);
break;
}
}

HandleTopLevelSingleDecl(*I);
}
return true;
}

另外一塊就是 void RewriteObjC::HandleTopLevelSingleDecl(Decl *D):


//===----------------------------------------------------------------------===//
// Top Level Driver Code
//===----------------------------------------------------------------------===//

void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) {
//
//...
//

// If we have a decl in the main file, see if we should rewrite it.
if (SM->isFromMainFile(Loc)) // SM = SourceManager ; Loc = SourceLocation
return HandleDeclInMainFile(D);
}

別忘了瞧瞧 HandleDeclInMainFile 做了甚麼事囉!裡頭有豐富的 type checking 以及對應的處理機制,最後,則是文字取代的部分:


void ReplaceText(SourceLocation Start, unsigned OrigLength, StringRef Str) {
// If removal succeeded or warning disabled return with no warning.
if (!Rewrite.ReplaceText(Start, OrigLength, Str) || SilenceRewriteMacroWarning)
return;
Diags.Report(Context->getFullLoc(Start), RewriteFailedDiag);
}

如此一來,對 Clang Rewriter 的架構也熟悉了!


2012年5月24日 星期四

[OSX] 使用開機光碟安裝、重灌 Mac OS X Lion @ Mac mini

01

最近很忙,很久沒開啟 Mac mini 了,順便就把它升到 Lion 了。只是從 Mac Snow Leopard 10.6.8 升到 Lion 後,很多東西都保留了下來,對於大部分的人都很夠用,但我又開始在想,如果想要重灌該怎辦?這安裝方式不像以前購買 Mac mini 附的安裝光碟,可以從桌面上點選幾下就可以光碟開機、刪除硬碟資料並安裝 Mac OS X,所以,我找了一陣子才發現該怎樣光碟開機 :P 偏偏我的鍵盤是 PS/2 轉接 USB 後再加個 KVM,重開機的熱鍵少說也試了十多次吧 :P

關於 Mac OS X 開機熱鍵:Intel 型 Mac 開機組合鍵

實在是光碟開機一直沒成功,就改用 Startup Manager 方式,也就是開機時 + Option 鍵的方式(一般鍵盤是 ALT 鍵),試了幾次比較能抓住訣竅 XD 就是聽到開機聲音後馬上接著按(不要等音效播完),如此一來就能進去設定選單。

04

接著就接近以前 Snow Leopard 安裝光碟一樣,可以先把硬碟處理一下,再接著重裝 Lion 囉!

06

附帶一提,如果從 Startup Manager 進去,並點選 OS X Lion Recovery HD 進去,清完硬碟後,直接點選重新安裝 Lion 時,此時會要求透過網路從 App Store 下載,這時若有 USB 安裝方式的話,可以選擇重新選擇啟動硬碟並選擇安裝來源的媒介,這樣就可以透過 USB 或光碟來安裝了,就不需要重新從網路下載。

[OSX] Mac OS X Lion 軟體清單及偏好設定 @ Mac mini

Mac OS X Lion

前幾天裝了 Ubuntu 12.04 Desktop 版後,發現內鍵的桌布配色真不錯,雖然只是裝在 Virtualbox 裡頭,也令人感到清新。今晚就手癢也把 Mac mini 重灌完啦,神清氣爽。

每次安裝的軟體及設定越來越少了?不知算不算走回 command-line 的生活呢?


  • 文字編輯


    • 偏好設定 -> 預設純文字 && 字型大小 14

    • 保留在 Dock 上

  • 終端機


    • 偏好設定 -> 設定 -> Pro 預設 && 字型大小 14

    • 保留在 Dock 上

  • Yahoo! KeyKey (Yahoo!奇摩輸入法)


    • 系統偏好設定 -> 語言與文字 -> 輸入來源 -> 勾選 Yahoo 奇摩輸入法

  • Skype


    • 偏好 -> 音效影像 -> 麥克風&揚聲器 -> USB PnP Sound Devices (由於我多買一支 USB 音效卡,額外再設定 Skype 播放收音的位置)

    • 偏好 -> 警示 -> 細節 -> 聯絡人可接聽/聯絡人狀態轉為無法接通 -> 取消 播放音效 & 顯示內建的通知訊息

    • 偏好 -> 隱私 -> 取消 "允許 Skype 使用非個人身分資訊作為第三方廣告服務用途"

    • 保留在 Dock 上 & 登入自動啟動

  • Pidgin

  • Filezilla

  • Firefox


    • 工具 -> 附加元件 -> firebug、新同文堂

    • 檢視 -> 工具列 ->顯示書籤列、取消同文堂

    • 偏好 -> 一般 -> 設定首頁

    • 偏好 -> 個人隱私 -> 不被追蹤、不保留歷史紀錄

    • 安裝 Flash player

  • Google Chrome


    • 設定 -> 顯示首頁按鈕、顯示書籤列、設定首頁、取消翻譯閱讀網頁、取消記錄與詢問密碼

    • 擴充功能 -> 新同文堂、XMarks Bookmark Sync、Google 閱讀器通知程式 (由 Google 提供)、Google Mail Checker

2012年5月21日 星期一

Time Station

TimeStation


該怎麼說呢?開始感覺到時間的不夠用了,人生不像大學期中期末考前,一夜不睡,至少可以追到七八成。