Postingan ini sebagai catatan pribadi dan mudah-mudahan bermanfaat untuk yang kebetulan harus “kecemplung” debugging aplikasi di Solaris dengan mesin SPARC. Sebagai catatan berikut adalah mesin yang saya pergunakan:
1 |
SunOS ###stripped### 5.10 Generic_147440-19 sun4v sparc sun4v |
Sedangkan file executable binary-nya adalah:
1 |
###stripped###: ELF 64-bit MSB executable SPARCV9 Version 1, UltraSPARC3 Extensions Required [CBCOND VIS3 VIS], dynamically linked, not stripped |
Tools
Sebelum memulai debugging di Solaris, sebenarnya ada beberapa tools yang disediakan oleh Solaris untuk keperluan debugging live appication. Tools tersebut adalah dtrace dan mdb. Untuk saat ini saya lebih prefer menggunakan mdb karena kebutuhan untuk melakukan patching kecil pada executable file sehingga perlu diketahui offset bytecode yang akan di-patch, dan hal ini bisa dicapai dengan mdb.
Selain mdb, perlu disiapkan adalah dokumen manual terutama instruction set sparcv9. Yang sayangnya saya tidak bisa menemukannya di internet mapping bytecode dengan instruction set yang diharapakan di sparcv9. Sebagai tools tambahan, dan banyak membantu adalah Online Disassembler. Situs ini menyediakan disassembler untuk berbagai tipe prosesor yang salah satunya adalah sparcv9.
Tools terakhir adalah hex editor, saat ini saya menggunkan HxD, karena kemudahan dan kebetulan saat ini menggunakan Windows di laptop kantor.
Solaris Modular Debugger
Inti dari tool debugging adalah kita bisa melakukan trace instruksi yang dilakukan oleh sebuah proses atau aplikasi, kemudian melakukan intercept pada bagian proses tertentu untuk dianalisa lebih jauh. Dalam postingan ini saya hanya akan memberikan beberapa command yang dipergunakan untuk proses debugging hingga pada akhirnya dapat menemukan lokasi bytecode yang harus dipatch.
Untuk command-command lain di mdb sepertinya banyak dan dapat ditemui di situs Oracle,
Untuk memulai debugging aplikasi dengan mdb (dan banyak debugger lainnya) dapat dipilih apakah melakukan debug pada file binary atau pada proses aplikasi yang berjalan. Untuk kebutuhan dynamic analysis saya menggunakan yang kedua.
1 |
>mdb -p 1024 |
Sebagai contoh saya mencoba menjalankan mdb untuk melakukan debugging proses aplikasi yang berjalan dengan pid=1024
.
List Functions
Karena kebetulan binary yang akan dipatch adalah not stripped, maka nama-nama fungsi dapat dilihat dengan mdb. Command yang dipergunakan adalah:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
> ::nm -t func Value Size Type Bind Other Shndx Name 0x000000010009fe80|0x000000000000002c|FUNC |LOCL |0x0 |10 |getreg 0x000000010009fec8|0x000000000000002c|FUNC |LOCL |0x0 |10 |putreg 0x000000010009fef4|0x0000000000000020|FUNC |LOCL |0x0 |10 |get_fregpair_index 0x000000010009ff30|0x00000000000000bc|FUNC |LOCL |0x0 |10 |verify_asi 0x00000001000a2a54|0x00000000000003b8|FUNC |LOCL |0x0 |10 |reinit_task 0x00000001000a2e0c|0x000000000000005c|FUNC |LOCL |0x0 |10 |proc_clear_fa_structures 0x00000001000a2e68|0x0000000000000120|FUNC |LOCL |0x0 |10 |fa_send_rsp 0x00000001000a2f88|0x00000000000001b0|FUNC |LOCL |0x0 |10 |standard_authorization 0x00000001000a3138|0x0000000000000090|FUNC |LOCL |0x0 |10 |make_default_flex_action 0x00000001000a36d8|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_dbupd_fp 0x00000001000a37a8|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_dbupd_fp_rev 0x00000001000a3878|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_dbupd_rev 0x00000001000a3948|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_dbupd 0x00000001000a3ff0|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_pre_fp 0x00000001000a40c0|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_pre_fp_rev 0x00000001000a4190|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_pre_rev 0x00000001000a4260|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_pre 0x00000001000a4a74|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_si_fp 0x00000001000a4b44|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_si_fp_rev 0x00000001000a4c14|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_si_rev 0x00000001000a4ce4|0x00000000000000d0|FUNC |LOCL |0x0 |10 |sa_msg_si 0x00000001000ac730|0x0000000000000280|FUNC |LOCL |0x0 |10 |parse_cref_pin_resp > |
Dari command nm
, dapat diketahuai pula offset lokasi bytecode untuk fungsi tersebut pada binary file. Sebagai contoh function sa_msg_pre
, dapat kita temukan pada offset 0xa4260
.
Disassembly
Untuk melakukan disassembly pada mdb dapat menggunkan command dis
, struktur commandnya adalah offset::dis
atau function_name::dis
. Contoh saya akan melakukan disassembly sebuah function sa_msg_pre:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
> sa_msg_pre::dis sa_msg_pre: save %sp, -0xb0, %sp sa_msg_pre+4: sethi %hi(0x100000), %i5 sa_msg_pre+8: sethi %hi(0x100000), %i4 sa_msg_pre+0xc: or %i5, 0x241, %i3 sa_msg_pre+0x10: or %i4, 0x3f4, %l7 sa_msg_pre+0x14: sllx %i3, 0xc, %l6 sa_msg_pre+0x18: add %l6, 0xcf0, %l4 sa_msg_pre+0x1c: sllx %l7, 0xc, %l5 sa_msg_pre+0x20: ldx [%l5 + 0xaf8], %o3 sa_msg_pre+0x24: mov 0x2, %o0 sa_msg_pre+0x28: add %l4, 0x178, %o2 sa_msg_pre+0x2c: call +0x163cf4 sa_msg_pre+0x30: mov %l4, %o1 sa_msg_pre+0x34: cmp %i2, 0x4 sa_msg_pre+0x38: bge,pn %icc, +0x28 sa_msg_pre+0x3c: nop sa_msg_pre+0x40: cwbe %i2, 0x1, +0x44 sa_msg_pre+0x44: nop sa_msg_pre+0x48: cwbe %i2, 0x2, +0x44 sa_msg_pre+0x4c: nop sa_msg_pre+0x50: cwbe %i2, 0x3, +0x5c sa_msg_pre+0x54: nop sa_msg_pre+0x58: ba +0x5c sa_msg_pre+0x5c: sethi %hi(0x100000), %i1 sa_msg_pre+0x60: be,pn %icc, +0x34 sa_msg_pre+0x64: cmp %i2, 0x67 sa_msg_pre+0x68: be,pt %icc, +0x34 sa_msg_pre+0x6c: nop sa_msg_pre+0x70: cmp %i2, 0x68 sa_msg_pre+0x74: be,pt %icc, +0x30 sa_msg_pre+0x78: nop sa_msg_pre+0x7c: ba +0x38 sa_msg_pre+0x80: sethi %hi(0x100000), %i1 sa_msg_pre+0x84: call +0xb248 sa_msg_pre+0x88: restore %g0, 0x0, %g0 sa_msg_pre+0x8c: call +0xed5c > |
Breakpoint
Untuk melakukan breakpoint pada offset tertentu atau fungsi tertentu dapat menggunakan command offset:b
atau function_name:b
. Sebagai contoh saya melakukan breakpoint fungsi sa_msg_pre:
1 |
> sa_msg_pre:b |
Untuk melihat list breakpoint:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
> $b ID S TA HT LM Description Action ----- - -- -- -- ---------------------------------------- ---------------------- [ 1 ] + T 0 0 stop on SIGINT - [ 2 ] + T 0 0 stop on SIGQUIT - [ 3 ] + T 0 0 stop on SIGILL - [ 4 ] + T 0 0 stop on SIGTRAP - [ 5 ] + T 0 0 stop on SIGABRT - [ 6 ] + T 0 0 stop on SIGEMT - [ 7 ] + T 0 0 stop on SIGFPE - [ 8 ] + T 0 0 stop on SIGBUS - [ 9 ] + T 0 0 stop on SIGSEGV - [ 10] + T 0 0 stop on SIGSYS - [ 11] + T 0 0 stop on SIGXCPU - [ 12] + T 0 0 stop on SIGXFSZ - [ 13] + 0 0 stop at sa_msg_pre - |
Untuk menghapus breakpoint gunakan command :d {nomor_breakpoint}
contohnya untuk menghapus breakpoint terakhir (nomor 13) : :d 13
.
Online Disassembler
Tools ini memudahkan kita untuk membuat bytecode yang akan dipergunakan untuk mengganti bytecode asli dari aplikasi / modul. Sayang saat postingan ini dibuat, situs tersebut sedang offline (selalu mendapat “Server Error (500)”). Jadi untuk detilnya saya belum bisa menuliskan di postingan ini.
Untuk kasus saya berikut adalah bagian function yang perlu dipatch yaitu pada line 12:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
> 1000d9828::dis -a 1000d9800 add %g4, 0xb02, %o2 1000d9804 ldub [%fp - 0x1d6], %o1 1000d9808 btst 0x20, %o1 1000d980c be,pn %icc, +0x144 1000d9810 add %i0, 0x290, %i4 1000d9814 ldd [%fp - 0x2c1], %d2 1000d9818 mov 0x2, %o2 1000d981c call +0x12d218 1000d9820 mov %i4, %o0 1000d9824 tst %o0 1000d9828 be,pn %icc, +0x12c 1000d982c mov %i2, %o1 1000d9830 call +0x124b10 1000d9834 nop 1000d9838 add %fp, -0xb39, %o1 1000d983c mov 0x2, %o2 1000d9840 mov %i4, %o0 1000d9844 call +0x12cb64 1000d9848 std %d0, [%fp - 0xb39] 1000d984c mov 0x4, %o0 1000d9850 ldx [%fp - 0xb39], %o3 |
Instruksi be,pn
adalah padanan untuk je
jika di mesin x86, melihat referensi di situs ORACLE be
artinya adalah “branch on equal”. Dan memang sepadan dengan je
(jump if equal).
Untuk kasus saya, saya perlu merubah be
ini menjadi ba
(branch always). Mari kita lihat instruksi tersebut dalam bytes hex.
1 2 |
> 1000d9828::dump -f -e 1000d9828: 0240004b 9210001a 400492c4 01000000 |
Dengan command dump
, kita bisa mengetahui ternyata instruksi be,pn
dengan parameternya memiliki nilai bytes: 0x0240004b
, lebih tepatnya 0x0240
, sedangkan 0x004b
merupakan nilai parameter instruksinya. Selanjutnya, adalah mencoba mencari nilai yang tepat untuk ba
. Karena keterbatasan referensi, maka disinilah peran Online Disassembler (ODA).
ODA dengan mudah melakukan encoding/decoding susunan bytes yang diinput menjadi pseudo code instruksi sparcv9. Dan akhirnya saya temukan bahwa untuk ba
nilai instruksi dalam bytes nya adalah: 0x1080
.
Dengan demikian patching dapat dilakukan dengan merubah 2 bytes dari binary executable. Berikut adalah hasil akhirnya:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
> 1000d9828::dis -a 1000d9800 add %g4, 0xb02, %o2 1000d9804 ldub [%fp - 0x1d6], %o1 1000d9808 btst 0x20, %o1 1000d980c be,pn %icc, +0x144 1000d9810 add %i0, 0x290, %i4 1000d9814 ldd [%fp - 0x2c1], %d2 1000d9818 mov 0x2, %o2 1000d981c call +0x12d218 1000d9820 mov %i4, %o0 1000d9824 tst %o0 1000d9828 ba +0x12c 1000d982c mov %i2, %o1 1000d9830 call +0x124b10 1000d9834 nop 1000d9838 add %fp, -0xb39, %o1 1000d983c mov 0x2, %o2 1000d9840 mov %i4, %o0 1000d9844 call +0x12cb64 1000d9848 std %d0, [%fp - 0xb39] 1000d984c mov 0x4, %o0 1000d9850 ldx [%fp - 0xb39], %o3 |