//---------------------------------------------------------------- // seestack.s (written for Linux kernel version 2.6.11) // // This program displays a hexadecimal and ascii dump of the // active portion of this program's stack as it existed upon // entry to the program's .text section. The initial values // in registers ESP and EBP are displayed, together with the // upper and lower bounds for the task's current stack-area. // // assemble using: $ as seestack.s -o seestack.o // and link using: $ ld seestack.o eax2hex.o hex2eax.o \ // -o seestack // // programmer: ALLAN CRUSE // written on: 13 FEB 2006 // revised on: 15 FEB 2006 -- to scan for stack-segment info // revised on: 18 FEB 2006 -- to show dump of "active" stack //---------------------------------------------------------------- # manifest constants .equ sys_exit, 1 .equ sys_read, 3 .equ sys_write, 4 .equ sys_open, 5 .equ O_RDONLY, 0 .equ STDOUT, 1 .equ BUFSIZE, 4096 .section .data filename: .asciz "/proc/self/maps" # pseudo-file's name legend: .ascii "[stack]" # label on stack-region info msg1: .ascii "\nstack-region: " span: .ascii "xxxxxxxx-xxxxxxxx \n\n" len1: .int . - msg1 msg2: .ascii "" buf1: .ascii "xxxxxxxx: " buf2: .ascii "xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx " buf3: .ascii "xxxxxxxxxxxxxxxx \n" len2: .int . - msg2 msg3: .ascii "\nentry-values: esp=" rESP: .ascii "xxxxxxxx ebp=" rEBP: .ascii "xxxxxxxx \n\n" len3: .int . - msg3 .section .bss filesiz: .space 4 # holds the pseudo-file size file_id: .space 4 # holds the pseudo-file's ID buf: .space BUFSIZE # holds the pseudo-file data len: .space 4 # holds current line's length ptr: .space 4 # holds pointer to stack-line esp: .space 4 # holds initial value of ESP ebp: .space 4 # holds initial value of EBP .section .text _start: # save the initial values found in registers ESP and EBP movl %esp, esp # store the ESP value movl %ebp, ebp # store the EBP value # open the pseudo-file for reading mov $sys_open, %eax # setup service ID-number lea filename, %ebx # setup pointer to filename mov $O_RDONLY, %ecx # specify file's access-mode int $0x80 # invoke the kernel service mov %eax, file_id # save pseudo-file's handle # read from the pseudo-file mov $sys_read, %eax # setup service ID-number mov file_id, %ebx # setup the file's handle lea buf, %ecx # setup the buffer address mov $BUFSIZE, %edx # and maximum bytes to read int $0x80 # invoke the kernel service mov %eax, filesiz # save count of bytes read # now we enter a loop which examines each line in the buffer # in order to determine (1) its length, and then (2) whether # or not that line describes this task's stack-segment. The # start-address of the line describing the stack is saved as # 'ptr' so we can then write it to the display-device. Note # that each line in the pseudo-file includes a 'legend' that # begins in column number 49 and describes a memory-segment. xorl %ebx, %ebx # setup initial buffer index cld # perform forward processing nxline: leal buf(%ebx), %esi # point ESI to current line # scan the current line for its end-of-line ascii-code movl %esi, %edi # copy line-pointer to EDI movl filesiz, %ecx # total size of buffer data subl %ebx, %ecx # minus data in prior lines movb $'\n', %al # setup target-byte in AL repne scasb # scan for end-of-line mark subl %esi, %edi # length is finish - start movl %edi, len # save this line's length # check the current line for the "[stack]" legend leal 49(%esi), %edi # address of legend-field leal legend, %esi # & legend-pointer in ESI movl $7, %ecx # legend-length into ECX repe cmpsb # compare the two strings je found # strings agree? save EBX # advance line-offset in EBX to the following line addl len, %ebx # add line-length to EBX cmpl filesiz, %ebx # check: EBX < filesize? jb nxline # yes, more lines to scan jmp quit # else scanning is done found: # save a pointer to the current line describing the stack leal buf(%ebx), %esi # get this line's address movl %esi, ptr # and save for use below # format the information for message #1 leal span, %edi # point EDI to msg-field movl ptr, %esi # point ESI to buf-field call hex2eax # convert string to int call eax2hex # convert int to string addl $9, %edi # advance to next source addl $9, %esi # advance to next dest'n call hex2eax # convert string to int call eax2hex # convert int to string # save the stack-region's upper-bound for use below movl %eax, ptr # save the upper-address # now show message #1 movl $sys_write, %eax # setup service ID-number movl $STDOUT, %ebx # setup device ID-number leal msg1, %ecx # point to relevant line movl len1, %edx # and setup line's length int $0x80 # invoke kernel service # show "active" stack-area from higher to lower addresses nxpara: subl $16, ptr # move down one paragraph movl ptr, %eax # load paragraph address cmpl esp, %eax # beneath "active" stack? jb fini # yes, no more to display # format the paragraph's address at 'buf1' leal buf1, %edi # point EDI to msg-field call eax2hex # convert value to string # format the paragraph's hex dump at 'buf2' leal buf2, %edi # point EDI to msg-field movl ptr, %esi # point ESI to paragraph movl $4, %ecx # count of longs in para nxhex: movl (%esi), %eax # setup next long in EAX call eax2hex # convert value to string addl $10, %edi # advance EDI to next field addl $4, %esi # advance ESI to next long loop nxhex # and do another long # format the paragraph's ascii dump at 'buf3' leal buf3, %edi # point EDI to msg-field movl ptr, %esi # point ESI to paragraph movl $16, %ecx # count of bytes in para nxasc: movb (%esi), %al # setup next byte in AL cmpb $0x20, %al # char preceeds 0x20? jb dotit # yes, it's nonprintable cmpb $0x7E, %al # char follows 0x7E? ja dotit # yes, it's nonprintable jmp useit # else we can print it dotit: movb $'.', %al # replace it with period useit: movb %al, (%edi) # place char into buffer incl %edi # advance dest'n pointer incl %esi # advance source pointer loop nxasc # and do another byte # now show message #2 movl $sys_write, %eax # setup service ID-number movl $STDOUT, %ebx # setup device ID-number leal msg2, %ecx # point to relevant line movl len2, %edx # and setup line's length int $0x80 # invoke kernel service jmp nxpara # now do another paragraph fini: # format the information for message #3 movl esp, %eax # recover saved ESP-value leal rESP, %edi # point EDI to msg-field call eax2hex # convert value to string movl ebp, %eax # recover saved ESP-value leal rEBP, %edi # point EDI to msg-field call eax2hex # convert value to string # now show message #3 movl $sys_write, %eax # setup service ID-number movl $STDOUT, %ebx # setup device ID-number leal msg3, %ecx # point to relevant line movl len3, %edx # and setup line's length int $0x80 # invoke kernel service quit: # terminate this program mov $sys_exit, %eax # setup service ID-number xor %ebx, %ebx # return 0 as exit-code int $0x80 # invoke kernel service .global _start .end