2012/06/29

virtualbox how to shrink vdi 檔如何壓縮?

明明已經把系統空間空出來了,可是 vdi 檔卻是愈長愈大,之前也不是很在意,主要是這次是要給別人用的,檔案太大不方便傳輸。要把明明系統不大,但是 vdi 檔卻相對非常大的檔縮小是可能的,會發生這樣的事主要是我在機器裡面編譯整個 android, 事後雖然 make clean 仍然不會因此變小,甚至還有加檔的話,vdi 檔仍然繼續變大....

1. guest 系統裡面請安裝 zerofree, 它不大,作用就是把已經刪除的 inode 資料清空,不然的話檔案系統會繼續往後長
2. 該 guest 系統用個開機光碟開機,當然我是用 iso 檔,一樣的
3. 光碟開機後進試用模式,掛載時請使用唯讀:
    mount /dev/sda1 /mnt -o ro
4. /mnt/usr/sbin/zerofree /dev/sda1

之後將 gesut os 關機,並回到 host 系統
5. 參考這篇VboxManage modifyvdi /path/to/your/VM.vdi compact
6. VboxManage clonehd  /path/to/your/VM.vdi  name-of-clone-vm.vdi
到此已經把 vdi 縮小。
順便講一下,要複製 vdi 請勿直接用 copy, 因為那樣的話虛擬磁碟的 UUID 會是相同的,請用上面的命令來複製產生新的虛擬磁碟

2012/06/21

daily update backup file 每日更新備份檔


有次幫朋友解決她的系統,因為她對 Linux 是門外漢,負責人又離職了,而系統首先是董事長的信無法收發,發現的是積存太大,爆了。後來又發現所有人都無法登入,一查,發現的是整顆硬碟爆了。
結論如下:
1. 該系統是磁碟陣列,但是只裝一顆硬碟。
2. 那顆硬碟只有 300G, 給 var, home 各約一半,大略上說啦,信箱當然在 /var/spool/mail 下,卻備份在 /home 下
3. 每週備份一次整個 /var 及 /home 
有發現問題嗎?問題來了,還不止一個,有誰看出來了嗎?整個!還是整個 /home!!!!
暫時解決方案就是把舊的備份檔砍了,只留一個最新的,而 /home 則是整個砍了。/var 還沒什麼大問題,比較嚴重的也只有她家董事長的信箱一個人就占了 1GB, 不大啦,但是每週備份也就不小喔。

而 /home 則成等比級數成長,所以該負責員工一離職,一週左右就出問題了。現在提供一下要更新備份檔的作法參考如下:

先初始一個第0階的備份檔:
$ tar --create --listed-incremental ./game.snar --gzip \
    --file game_`date +%F`.tar.gz game/ 2>&1 >> game_`date +%F`.log
接下來,備份時可以只針對比第0階的備份檔新的才更新,其中時間的參考檔是 game.snar,所以這個檔請不要亂刪。之後產生的都稱之為 level 1 的備份檔。
$ tar --create --listed-incremental ./game.snar --gzip \
    --file game_`date +%F`.tar.gz game/ >> game_`date +%F`.log
要還原的話,參考命令如下:
$ for t in game_2011-10-2*.tar.gz; \
    do tar --extract --incremental --gzip --file $t; done

2012/05/24

google android market play to PC

http://www.hacktabs.com/download-android-apps-apk-to-your-pc-from-android-market-or-google-play/

2012/05/22

RS232

有些字眼其實很容易混淆人,不久前,有同事就在問『什麼是 RS232』?『跟 Serial Port的差異』?『那什麼又是 COM Port』?

不管這個,先回想一下,在 linux 上要對 COM Port 做 I/O 其實很簡單,一般是用 minicom 這支工具,但是基本觀念若懂的話,也可以在 console mode 下命令,可以參考這篇

1. 確認你的 COM port, 像我的是 /dev/ttyUSB0
2. 確認設定,例如我的是 115200, 8N1, off
--> stty -F /dev/ttyUSB0 raw ispeed 115200 ospeed 115200 cs8 -ignpar -cstopb -ixon 


3. 讀取: cat /dev/ttyUSB0, 或是上面那篇參考文件裡面也有些技巧可用
4. 寫入 echo "CONTENT" > /dev/ttyUSB0

PS1: 步驟2的設定,只要在同一個 console 執行過一次,當然不同的 console(例如重開機,重登入等)都得設定過一次,也可以寫在 .bashrc 中
PS2: 步驟 3, 4 可以同時做,也就是用一個 console 做 cat, 這樣不會離開,再用另一個 console 寫入

2012/04/10

apt-rdepends

http://blog.hartwork.org/?p=108

2012/04/07

source navigator on ubuntu 12.04


執行底下的 script


#!/bin/bash
wget http://svn.exactcode.de/t2/trunk/package/develop/sourcenav-ng/tk-lastevent.patch
wget http://nchc.dl.sourceforge.net/sourceforge/sourcenav/sourcenav-6.0.tar.gz

tar zxvf sourcenav-6.0.tar.gz
cp tk-lastevent.patch sourcenav-6.0
cd sourcenav-6.0
patch -p1 < tk-lastevent.patch
./configure
make
sudo make install

2012/04/02

ubuntu 12.04 build android

http://endroid.blogspot.com/2011/07/android-development-notes.html

2012/02/06

在揮別的時候.不要說再見 baby, don't say good-bye

我總是最耀眼的那一個。朋友,珍重....

2012/02/03

android api diff ?

不知道從何時開始,不知道怎麼找到的,因此跟大家分享一下 要研究 android 各級 api 之間的差異的話,用底下的界面非常方便: 例如要研究 android 4.0 http://developer.android.com/sdk/api_diff/14/changes.html http://developer.android.com/sdk/api_diff/15/changes.html 其中 14, 15 是 api level, 可以從底下找資訊, 值得注意的是,android 各 api level 跟版本的關係有點亂....舉個例來說,我的手機早期自動更新到 2.3.6, 但在 AOSP 上面根本找不到

2012/01/31

超感動 ICS4.0.3

我的 Nexus S 手動升級到 4.0.3!!!!

讀者請注意,若您因為看本文,照著操作卻導致手機故障,作者概不負任何責任。

☆☆經本人實際測試過可行,不代表您的手機也可行☆☆


  1. 首先,下載 Android ICS4.0.3更新影像檔 ,這一步您可以直接用手機下載,或是用 NB 下載再傳上去
  2. 將之更改名稱為 update.zip, 事實上這只是怕您升級之後忘了殺掉,久了又忘了這個檔案的功用,如果您習慣夠好,也可以不必更名
  3. 如果您是用手機下載,請跳到下一步,否則請用 usb cable 連接電腦,若您不會這一步,請教會的人吧,或是上網查怎麼用 usb cable 讓 NB/Phone 互傳檔案。記得放在 /sdcard 最上層(應該等於 /mnt/sdcard)。
  4. 用手機下載的檔案是放在 /download 請用「文件管理器」這類的工具將之更名+移至 sdcard  最上層(/mnt/sdcard)。
  5. 做完 step 3, 4 之後,請關機.....也就是長按 Power 鍵,按確認關機
  6. 接下來要進一般人不會看到的畫面.....是還不會出問題,可以玩玩看
    先按著 V+ 不放, 也就是平常調聲音變大的那個鈕,通常是指「左側上方」那個按鍵, 然後....
    再按著 Power 鍵 ==> 很快就開機進 bootloader 畫面,是純文字的,所以別奇怪
  7. 在 bootloader 畫面的操作只有兩個:
    V+ 向上, V- 向下, 然後 Power 是確認: 噫?是三個?好吧,我們的算法不一樣
  8. 此時應該很快會看到一個類似警告標誌,很像而已,三角形附近還有個小綠人....
     
  9. 請注意
    再接下去就要破壞你的手機啦!!!!請先按著 Power 鍵不放,再按 V+,跟 step 6 順序不太一樣。然後就會再進一個選單....操作方式一樣.....
  10. 此時請選『Apply update from /sdcard』,操作並選擇 update.zip 或是您下載的檔案VQ8PQk_V.zip
  11. 確認更新......手機在這一步之後原系統會被破壞.....不過當然一些常見的設定會保留,別怕,就給他更新下去啦。
  12. 更新大概也只需要等個5分鐘吧,我沒仔細量,但是很快.....之後就從選單選「reboot」
  13. 如果開機時,能看到亂七八糟的方塊閃來閃去的話......恭喜!!!!
    否則.....我沒發生這個否則,請送修.....

2012/01/20

多媒體檔案處理 ffmpeg, netpbm...

用 ffmpeg 來處理影片及照片是非常理想的。會寫這個議題,主要是因為我想節省上傳到 blog 的時間。若仔細一點會發現,當我們把檔案上傳到 Picasa 或 blogger 時,所占用的空間比原始檔案小很多很多!其實是因為 google 有在伺服器端處理過。

上述現象我多年前一開始用 Picasa 就知道了,後來發現上傳到 blogger 的照片也會自動放到 Picasa。不過一向都很懶,最近閒閒的,就寫了幾個 script 用來處理影片及照片,這樣也可以節省上傳的時間。這一點不比較不知道,我們自己先處理過後,上傳節省的時間可真的是非常驚人啊!如果.........嘿嘿..........如果什麼我就不多說了,總之勤勞一點會讓自己省很多時間,而時間就是金錢啊!

上面連結是我整理的文件,裡面就有 script....系統當然要安裝 ffmpeg 及 netpbm 而且我在用的環境可不是 windows, 而是 ubuntu, 這一點對 windows 的朋友們只能說聲抱歉了!但是好消息是,這兩套軟體其實都有 windows 版的 ffmpegnetpbm , 請自行上網直取最新版,用法當然都一樣,只是請自行寫 windows 下的 .bat 檔來用吧。

上面的網址有人反應不通,可以再試一次,或是直接 copy 底下的內容,不過我懶得貼 USAGE, 每個指令的 USAGE 都不一樣,請自行編輯自己的 USAGE:

  • video2avi
    把影片轉成 avi 格式,而且大小是 320x240, 這是因為我要上傳到 blog 解析度剛好
    [ "$#" = "2" ] || usage
    ffmpeg -i $1 -vcodec mpeg4 -s 320x240 -b 300k -r 30 -acodec copy -ar 22050 -ab 64k -f avi $2
    
  • video2img
    把影片存成每秒 n 張的圖片
    [ "$#" = "3" ] || usage
    ffmpeg -i $1 -r $2 -f image2 $3
    
    範例: video2img MOV00001.mpg 10 micro-video-%03d
  • video-from-img
    [ "$#" = "3" ] || usage
    ffmpeg -i $1 -r $2 -f image2 -c:v libx264 -r 30 $3
    範例: video-from-img img%03d.png 1/5 out.mp4
      如果照片沒照順序,需要用以下的命令,請自行參考
    ffmpeg -i '*.png' -r 1 -f image2 -pattern_type glob -c:v libx264 out.mp4
  • video2mp3
    將影片中的音軌取出存成 mp3
    [ "$#" = "2" ] || usage
    ffmpeg -i $1 -vn -acodec libmp3lame -ab 192k $2
    
  • video2vcddvd
    將影片轉成 vcd 或是 dvd,可以分開成兩個指令較方便
    [ "$#" = "3" ] || usage
    [ "$2" = "vcd" ] && ffmpeg -i $1 -target ntsc-vcd $3
    [ "$2" = "dvd" ] && ffmpeg -i $1 -target ntsc-dvd $3
    
  • video_cut
    [ "$#" = "4" ] || usage
    ffmpeg -i $1 -ss $2 -t $3 -f image2 $4
    
    還有一種語法如下,只截一張:
    ffmpeg -i $1 -y -f  image2  -ss $2 -vframes 1  $3
    -ss 的時間單位也可以是秒,如下:
    ffmpeg -i $1 -y -f  image2  -ss $2 -vframes 1  $3
    
  • video_histogram
    如果影片偏暗或是偏亮,可以用這個方法將亮度調「平均」,因為是計算的,絕對無法真的平均,所以除非你不喜歡影片亮度再試。
    [ "$#" = "2" ] || usage
    rm -rf /tmp/my-video; mkdir -p /tmp/my-video/{orig,hhh}
    ffmpeg -i $1 -r 30 -f image2 /tmp/my-video/orig/%05d.pnm
    pushd /tmp/my-video/orig
    for i in `\ls`; do
      FILE=`echo $i| cut -d. -f1`;
      pnmhisteq $i > ../hhh/${FILE}.pnm;
    done
    popd
    ffmpeg -i /tmp/my-video/hhh/%05d.pnm -r 30 $2
    
  • img_resize - 用 ffmpeg
    將相片縮小成 1600x1200, 這是 blog 預設的圖片大小,而通常相機也都遠大於這解析度。另外大家可能不知道,相機為了盡可能保持影片資訊,雖然是有壓縮的,但是其實是調成盡可能保存影片資訊,只要調整一下壓縮比例至 99% 或是 90% 就大大降低檔案大小。總之一句話,經過這樣轉換後,照片大小縮小很多很多。
    底下指令因為太簡單,我並沒有寫成 script, 只是寫個範例
    ffmpeg -i $1  -s 1600x1200 a.jpg
  • img_resize 2 - 用 netpbm
    用 ffmpeg 處理照片有時會遇到無法讀取的問題,也就是有些相機的格式不被讀取, 譬如我就遇到如下的錯誤訊息:
    [mjpeg @ 0x139bcc0]error count: 71
    [mjpeg @ 0x139bcc0]error y=23 x=156
    Input #0, image2, from '20120206_133247.jpg':
      Duration: 00:00:00.04, start: 0.000000, bitrate: N/A
        Stream #0.0: Video: mjpeg, yuvj422p, 3264x2448, 25 tbr, 25 tbn, 25 tbc
    

    因此只好改用 netpbm 來轉換,轉換命令如下列範例:
    jpegtopnm 20120206_133247.jpg | pnmscale -xsize=1600 -ysize=1200 | pnmtojpeg - > aaa.jpeg
    
  • 將影片變成快動作/慢動作
    這功能要由 mencoder 來實作,底下也只是範例,可以自行改成 script。mencoder 功能一樣很強大,算是編輯影片必備,例如將照片合成時加上配樂。
    mencoder -ovc copy -nosound -speed 5 in.mpg -o fast.mpg
  • 切割音軌
    用另一個軟體做的範例,ffmpeg 也可以做到
    cdparanoia -B  : 整張 CD
    cdparanoida -B 3-7 : 只抓 3,4,5,6,7 音軌
    cdparanoia "2[:35.00]-2[2:30.00]" : 抓第二軌
    

文章共享


Linux 基本觀念+常用命令
regular expression and  ...
Android 系統初探 /proc, /sys and others

再探 /proc


2012/01/19

mm busybox on android tree

寫過一篇 cross compile busybox for android,因為剛剛看到一篇mm busybox on android tree,覺得不錯就貼上來。(註:編譯出來的檔案會小很多)

基本上相當簡單,照底下的做就行了....


  • cd $ANDROID/external/
  • git clone https://github.com/CyanogenMod/android_external_busybox.git --branch ics
  • cd android_external_busybox
  • mm
希望您能一切順利。這邊要提醒的是,這個 android_external_busybox 因為跟 android bionic 有很大的相關性,因此您得切換到與您的 android 版本相關的分支才行

若比對 gingerbread 與 ics 的差異...

  • Android.mk: BIONIC_ICS := false --> BIONIC_ICS := true
  • networking/nslookup.c: # define _res _nres  --> # define _res (*__res_get_state())
    這個變動若您在 android 需要寫程式對 dns 有需求的話,可能會遇到問題,請見這篇
  • util-linux/dmesg.c: 加了底下這些,不影響大局:
    diff -ruN busybox-gingerbread//util-linux/dmesg.c busybox-ics/util-linux/dmesg.c
    --- busybox-gingerbread//util-linux/dmesg.c     2012-01-19 17:23:20.415785436 +0800
    +++ busybox-ics/util-linux/dmesg.c      2012-01-19 17:10:43.165785088 +0800
    @@ -10,16 +10,24 @@
      */
    
     //usage:#define dmesg_trivial_usage
    -//usage:       "[-c] [-n LEVEL] [-s SIZE]"
    +//usage:       "[-c] [-n LEVEL] [-r] [-s SIZE] [-C]"
     //usage:#define dmesg_full_usage "\n\n"
     //usage:       "Print or control the kernel ring buffer\n"
     //usage:     "\n       -c              Clear ring buffer after printing"
     //usage:     "\n       -n LEVEL        Set console logging level"
    +//usage:     "\n       -r              Show level prefix"
     //usage:     "\n       -s SIZE         Buffer size"
    +//usage:     "\n       -C              Colored output"
    
     #include 
     #include "libbb.h"
    
    +#define COLOR_DEFAULT 0
    +#define COLOR_WHITE   231
    +#define COLOR_YELLOW  226
    +#define COLOR_ORANGE  166
    +#define COLOR_RED     196
    +
     int dmesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     int dmesg_main(int argc UNUSED_PARAM, char **argv)
     {
    @@ -29,11 +37,13 @@
            enum { 
                    OPT_c = 1 << 0,
                    OPT_s = 1 << 1,
    -               OPT_n = 1 << 2
    +               OPT_n = 1 << 2,
    +               OPT_r = 1 << 3,
    +               OPT_C = 1 << 4
            };
    
            opt_complementary = "s+:n+"; /* numeric */
    -       opts = getopt32(argv, "cs:n:", &len, &level);
    +       opts = getopt32(argv, "cs:n:rC", &len, &level);
            if (opts & OPT_n) {
                    if (klogctl(8, NULL, (long) level))
                            bb_perror_msg_and_die("klogctl");
    @@ -55,13 +65,37 @@
                    return EXIT_SUCCESS;
    
    
    -       if (ENABLE_FEATURE_DMESG_PRETTY) {
    +       if ((ENABLE_FEATURE_DMESG_PRETTY || (opts & OPT_C)) && !(opts & OPT_r)) {
                    int last = '\n';
    -               int in = 0;
    +               int in = 0, l, color;
    +               char pfx[16], *lvl;
    
                    /* Skip <#> at the start of lines */
                    while (1) {
                            if (last == '\n' && buf[in] == '<') {
    +                               if (opts & OPT_C) {
    +                                       lvl = buf + in + 1;
    +                                       sscanf(lvl, "%d", &level);
    +
    +                                       switch (level) {
    +                                       case 1:
    +                                       case 2:
    +                                       case 3: color = COLOR_RED;    break;
    +                                       case 4: color = COLOR_ORANGE; break;
    +                                       case 5: color = COLOR_YELLOW; break;
    +                                       case 7: color = COLOR_WHITE;  break;
    +                                       case 6: // common dmesg info
    +                                       default: color = COLOR_DEFAULT;
    +                                       }
    +
    +                                       if (color != COLOR_DEFAULT)
    +                                               l = sprintf(pfx, "%c[%d;%d;%dm",
    +                                                       0x1B, 38, 5, color);
    +                                       else
    +                                               l = sprintf(pfx, "%c[%dm", 0x1B, 0);
    +
    +                                       full_write(STDOUT_FILENO, pfx, l);
    +                               }
                                    in += 3;
                                    if (in >= len)
                                            break;
    @@ -72,9 +106,17 @@
                            if (in >= len)
                                    break;
                    }
    +
    +               if (opts & OPT_C) {
    +                       /* Reset default terminal color */
    +                       l = sprintf(pfx, "%c[%dm", 0x1B, 0);
    +                       full_write(STDOUT_FILENO, pfx, l);
    +               }
    +
                    /* Make sure we end with a newline */
                    if (last != '\n')
                            bb_putchar('\n');
    +
            } else {
                    full_write(STDOUT_FILENO, buf, len);
                    if (buf[len-1] != '\n')
    

2012/01/09

svn on windows 的帳號管理

先前寫過二篇 svn  相關的文,一篇是 svn 另一篇是 svn server on windows xp, 其實安裝都不會是太大問題,問題在於使用時....

首先,repository 的觀念並不是每個人都有,要從個人寫程式,進化到一群人寫程式,是不一定要版本控制的。反過來說,個人寫程式也應該要有版本控制的觀念才好。我先來解釋這個概念。

版本控制可以讓『寫程式』的人,可以追蹤舊版本、分支等等,而不必像大多數人用 'zip' 把目錄壓縮起來,或是整個目錄變成 copy project project.bak 這種方式。這是一個很重要的需求。版本控制通常都可以很容易就做 diff, patch, branch, merge 等等,這對多人合作開發是非常重要的需求。

接下來,該說的話,我在前文大概都寫過了,講一下我忘了講的部份,其實,每個 repository 跟 project 是「可以一樣」「也可以不一樣」,這個我不再多說,只是要再講一遍的是,以 svn 來說,它能對每個 repository 做存取權限的控管,找一下  conf 目錄就有了。

若是用 apache ,也就是用 http:// 或是 https:// 來存取的話,存取權限當然就是要在 apache 中設定。

若是用 svn:// 來存取的話,設定檔就是在 conf/ 目錄下的三個檔:passwd, authz, svnserve.conf。

正常來說 apache, svn 都要有自己的帳號管理,尤其 svn 的三個設定檔中的密碼竟然是明文的,所以非常不建議使用 svn 的內建控管機制。

好加在的是,apache 可以結合 windows 控管機制,這個我在前文中就有講了怎麼安裝。現在說說每個 repository 如何做管理?

最簡單的方法,就是在 repository 的目錄採用 windows 的網路芳鄰的分享機制來做. 如果不滿意,可以參考這篇來實作

2012/01/04

反組譯 c/c++ disassembly

這篇不是教人家怎麼反組譯,因為大部份都需要好的工具,就像要反組譯 android apk 可以用 smali 一樣。

在 android 上要反組譯 c/c++ 的執行檔是相當麻煩的,不過常用的 Linux  工具可以提供我們一個思考方向:nm, objdump, 甚至是 gdb。

寫在前面:其實是有你看這篇時心中想要的工具,不過好用的是要錢的,不要錢的我自己都編譯不了,但是還是提供一下資訊供大家參考: boomerang

objdump 是很常見的,網路上也有相當多的文件,有興趣的人可以自行找找看,或是參考這篇

我舉個簡單的例子來說明 nm, objdump

#include 

int sum(int a, int b){
  return a+b;
}

int main(int argc, char* argv[])
{
  int i, j;
  i = 10;
  j = i*2;
  printf ("Hello, %d + %d == %d\n", i, j, sum(i, j));
  return 0;
}

編譯: 通常拿到執行檔的時候,它的編譯選項是不可能加 -g 的(gcc -g hello.c -o hello),如果有的話,算是你幸運,可以直接下 objdump -S hello 就可以得到下面的結果(大部份都略過):

00000000004004f4 :
#include 

int sum(int a, int b){
  4004f4:       55                      push   %rbp
  4004f5:       48 89 e5                mov    %rsp,%rbp
  4004f8:       89 7d fc                mov    %edi,-0x4(%rbp)
  4004fb:       89 75 f8                mov    %esi,-0x8(%rbp)
  return a+b;
  4004fe:       8b 45 f8                mov    -0x8(%rbp),%eax
  400501:       8b 55 fc                mov    -0x4(%rbp),%edx
  400504:       8d 04 02                lea    (%rdx,%rax,1),%eax
}
  400507:       c9                      leaveq 
  400508:       c3                      retq   

上面可以見到 sum() 的程式碼......其實 main() 的也有,往下找....

0000000000400509 
: int main(int argc, char* argv[]) { 400509: 55 push %rbp 40050a: 48 89 e5 mov %rsp,%rbp 40050d: 48 83 ec 20 sub $0x20,%rsp 400511: 89 7d ec mov %edi,-0x14(%rbp) 400514: 48 89 75 e0 mov %rsi,-0x20(%rbp) int i, j; i = 10; 400518: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) j = i*2; 40051f: 8b 45 fc mov -0x4(%rbp),%eax 400522: 01 c0 add %eax,%eax 400524: 89 45 f8 mov %eax,-0x8(%rbp) printf ("Hello, %d + %d == %d\n", i, j, sum(i, j)); 400527: 8b 55 f8 mov -0x8(%rbp),%edx 40052a: 8b 45 fc mov -0x4(%rbp),%eax 40052d: 89 d6 mov %edx,%esi 40052f: 89 c7 mov %eax,%edi 400531: e8 be ff ff ff callq 4004f4 400536: 89 c1 mov %eax,%ecx 400538: b8 4c 06 40 00 mov $0x40064c,%eax 40053d: 8b 55 f8 mov -0x8(%rbp),%edx 400540: 8b 75 fc mov -0x4(%rbp),%esi 400543: 48 89 c7 mov %rax,%rdi 400546: b8 00 00 00 00 mov $0x0,%eax 40054b: e8 a0 fe ff ff callq 4003f0 return 0; 400550: b8 00 00 00 00 mov $0x0,%eax }
不過,問題是,我們拿到的執行檔應該是沒有加 -g 這個 debug 選項的,事實上,在沒有更好的工具時,有一個方法可以「觀察」,就是 nm -s hello (PS: 假設 gcc hello.c -o hello)
...
0000000000600e24 d __init_array_end
0000000000600e24 d __init_array_start
00000000004005f0 T __libc_csu_fini
0000000000400560 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000601020 A _edata
0000000000601030 A _end
0000000000400638 T _fini
00000000004003c8 T _init
0000000000400410 T _start
000000000040043c t call_gmon_start
0000000000601020 b completed.6557
0000000000000000 a crtstuff.c
0000000000000000 a crtstuff.c
0000000000601010 W data_start
0000000000601028 b dtor_idx.6559
00000000004004d0 t frame_dummy
0000000000000000 a hello.c
0000000000400509 T main
                 U printf@@GLIBC_2.2.5
00000000004004f4 T sum

此時可以見到程式中定義了 main, 使用(呼叫)了 printf(), 及 sum()
PS: 上面有很多底線開頭的符號,都可以直接略過,因為那都是「內建」符號

講到這邊,有人可能要大聲抗議,這怎麼叫反組譯啊!!!!我可沒說反組譯回 C/C++ source code.....若你能讀懂組合語言的話.....當然,正常程式寫作上,光函式名稱, 也就是符號表就常常暗示了很大的一部份程式運作了。

還有一個命令叫 strings, 上面無 -g 的 hello 也可以用 strings hello 得到下面結果:
/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
printf
__libc_start_main
GLIBC_2.2.5
fff.
=p       
l$ L
t$(L
|$0H
Hello, %d + %d == %d
看到最後一行的 hello, %d + %d == %d 了嗎?那就是出現在程式中的字串

最後最後,提供一個 debug 的工具叫 strace,我會提它是因為它也是 busybox  有提供的工具。
strace 的功能是「追蹤命令執行時所呼叫到的系統函式」,這一段說明恐怕你不容易了解,但是能追蹤系統呼叫通常也是解密的最重要線索,用法如下:
strace ./hello
PS: strace 後面要接的是執行的命令,因此是 ./hello, 而不是 hello
PS2: strace 還有一些參數,例如把輸入導到檔案之類的,可以自行上網查。