ラベル アセンブラ の投稿を表示しています。 すべての投稿を表示
ラベル アセンブラ の投稿を表示しています。 すべての投稿を表示

2010年2月24日水曜日

SBCLでバイト列を逆アセンブルする

Kernel/VM探検隊に参加しました。皆さんスペック高すぎです。参加したおかげで上がったテンションのまま、SBCLで遊んでみた。

1.SBCLにはネイティブコードコンパイラが備わっている。

2.CommonLispでは仕様でdisassemble関数が定義されている。

つまり、SBCLでバイト列を逆アセンブルことは簡単。たぶん。

ということでやってみた。

(defun disassemble-u8-list (u8-list)
(let ((len (length u8-list)))
(let ((alien (sb-alien:make-alien sb-alien:unsigned-char len)))
(unwind-protect
(progn
(loop :for i from 0
:for u in u8-list
:do (setf (sb-alien:deref alien i) u))
(sb-disassem:disassemble-memory (sb-alien:alien-sap alien) len))
(sb-alien:free-alien alien)))))

準備として、アセンブラで適当にコードを書く。

bits 32
section .text

global _start
_start:
mov eax, 4 ;write
mov ebx, 1 ;fd
mov ecx, ptr ;buf
mov edx, 6 ;size
int 0x80
mov eax, 1 ;exit
mov ebx, 0
int 0x80
ptr db 'Hello',10
>nasm -f elf32 test.asm
>ld -o test test.o
>./test
Hello
>nasm -f bin -o test.bin test.asm
>hd test.bin
00000000 b8 04 00 00 00 bb 01 00 00 00 b9 22 00 00 00 ba |..........."....|
00000010 06 00 00 00 cd 80 b8 01 00 00 00 bb 00 00 00 00 |................|
00000020 cd 80 48 65 6c 6c 6f 0a |..Hello.|
00000028

このバイト列を逆アセンブルしてみる。

>(disassemble-u8-list
'(#xb8 #x04 #x00 #x00 #x00 #xbb #x01 #x00 #x00 #x00
#xb9 #x22 #x00 #x00 #x00 #xba #x06 #x00 #x00 #x00
#xcd #x80 #xb8 #x01 #x00 #x00 #x00 #xbb #x00 #x00
#x00 #x00 #xcd #x80 #x48 #x65 #x6c #x6c #x6f #x0a))
; 08089CA8: B804000000 MOV EAX, 4
; AD: BB01000000 MOV EBX, 1
; B2: B922000000 MOV ECX, 34
; B7: BA06000000 MOV EDX, 6
; BC: CD80 INT 128
; BE: B801000000 MOV EAX, 1
; C3: BB00000000 MOV EBX, 0
; C8: CD80 INT 128
; CA: 48 DEC EAX
; CB: 65 GS-SEGMENT-PREFIX
; CC: 6C INSB
; CD: 6C INSB
; CE: 6F OUTSD
; CF: 0A00 OR AL, [EAX]
NIL

2回目のINT命令以降は文字列。objdumpの結果とくらべても間違いはなさそう。最後の0x0Aが0A00とされているが、メモリ上の次の値を読んでいそう。

2009年10月11日日曜日

QEMU,GDB,インラインアセンブラ

めもめも.

QEMU <—> GDB

最近QEMUでGDBサーバーとやらを使うとおいしいということを知ったのでメモ.

/* QEMU起動時に-sオプションを付けるとGDBサーバーが起動.-pでポート指定可能.デフォルトは1234. */
>qemu -fda floppy.img -boot a -s
/* gdb起動 */
>gdb file.bin
/* GDBサーバに接続 */
>>target remote localhost:1234

QEMUのオプション

/* QEMUモニタをターミナルに */
>qemu -fda floppy.img -boot a -monitor stdio
/* QEMUをcursesで */
>qemu -fda floppy.img -boot a -curses

GDBのコマンドなど.

n(ext)とs(tep)の違いは,nextが関数呼び出しを1行として扱うのに対し,stepは関数内に入ること.

GCCでもNASMでも-gオプションを付けるとデバッガ用に出力してくれるようだ.

/* GDBで毎回コマンドを打つのがメンドクサイ.ファイルにコマンドを書いておいて読み込む.-xオプション. */
>gdb -x script.gdb file.bin
/* 構造体の内容を表示(16進) */
>>p/x *(&structure[0])
/* メモリの内容を表示 */
>>x/10 &function
/* バックトレース表示 */
>>bt

インラインアセンブラ(GCC・GAS)

NASMを使っていたのでGCCのインラインアセンブラに触ったらエラーを連発してしまった.突っかかったところ,気を付けるところをメモしておく.

  • GAS
    • mov等のソースとデスティネーションが逆
    • 即値には$を付ける
    • レジスタには%を付ける
    • [esp + 4] -> 4(%esp)
    • mov,pop等の後にサイズを表すb,w,lなどが付く
    • global等の前に.が付く
    • 1行コメントは;ではなく#
  • インラインアセンブラ
    • __asm__ __volatile__( ... ); の...に文字列で書く
    • 1行ごとに文字列を書く場合,末尾に\\n\\tを付ける
    • 拡張構文は asm( "実行するアセンブリコード" : "=指定文字列" (出力先変数) : "指定文字列" (入力) : "破壊されるので退避してほしいレジスタ");
    • "実行するアセンブリコード"以外は省略可能.後ろに何も書かないなら:も省略可能(必須?).
    • "実行するアセンブリコード"に%0,%1...と書いたものと,入力に書いた変数等が順に対応する.指示文字列で他の値を指定できる.
    • "実行するアセンブリコード"にレジスタを書きたい場合,%%eaxのように%%を付ける