0

So I have this Assembly program where I'm trying to output some data using a call to printf, but it wont print the whole thing that I'm trying to print.

    .section .data
    output:
            .asciz "The processor Vendor ID is ‘%s’\n"

    .section .bss
    .lcomm buffer, 64
    .section .text

    .globl _start
    _start:
            pushq %rbx
            movq $0, %rax
            cpuid

            movq $buffer, %rsi
            movq $output, %rdi
            mov %ebx, 28(%rdi)
            mov %ecx, 32(%rdi)
            #mov %edx, 35(%rdi)

            movq $0, %rax
            call printf

            movq $60, %rax
            movq $0, %rdi
            popq %rbx
            syscall

This version prints absolutely nothing, however; this version:

    .section .data
    output:
            .asciz "The processor Vendor ID is ‘%s’\n"

    .section .bss
    .lcomm buffer, 64
    .section .text

    .globl _start
    _start:
            pushq %rbx
            movq $0, %rax
            cpuid

            movq $buffer, %rsi
            movq $output, %rdi
            mov %ebx, 27(%rdi)
            mov %ecx, 31(%rdi)
            #mov %edx, 35(%rdi)

            movq $0, %rax
            call printf

            movq $60, %rax
            movq $0, %rdi
            popq %rbx
            syscall

This version prints out The processor Vendor ID is Genuntel even though the offset only changed by one. If I include the commented line, the program doesn't print anything no matter what (I am aware that the offset is wrong, in the first example, but even if it is 36 it won't print). As such, I'm curious as to how the offset affects it so that it wont print at all for the first one but it prints for the second one.

Keep in mind that this is a school assignment, but I have been trying for days now and I can't seem to get it to work.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Ohunter
  • 343
  • 1
  • 2
  • 13
  • In both code samples you store the data into `output`, overwriting it (watch in debugger that part of memory, what happens), while you have `buffer` memory reserved elsewhere which can be used too (but it should be zero terminated string as second argument for `printf` .. the `.bss` section is zeroed when `main` is entered, so writing `cpuid` vendor string once and having at least +1 byte reserved space gives you also zero terminator guaranteed, but would you input strings of different lengths multiple times, you would have to write zero terminators as well to not get old values appended). – Ped7g Nov 06 '18 at 07:04
  • So you are doing `printf("bla bla – Ped7g Nov 06 '18 at 07:08

1 Answers1

1

This code looks like it's set up for you to store the string bytes into buffer, relative to RSI, so the %s conversion in the format string will print it. But with the string in .data instead of .rodata where you should put read-only data, yes you can overwrite bytes of the format string at runtime.

When you overwrite the \n, printf doesn't flush the output buffer because stdout is line buffered. You exit with sys_exit (direct system call) instead of call exit or returning from main, leaving the data un-printed. See Using printf in assembly leads to an empty ouput

You can use ltrace ./my_program to see the library function calls it makes.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • So I'm assuming that what you are trying to tell me is that I should replace the '%s' with the whole string rather than forcing the bytes into the buffer? How would I go about doing that? I understand the reason why, now I'm wondering how to fix it. – Ohunter Nov 06 '18 at 03:51
  • 1
    No, you should `mov %ebx, (%rsi)` so you eventually call `printf("blah blah '%s'\n", "GenuineIntel");` instead of rewriting the format string to `printf("blah blah 'GenuineIntel", unused_rsi_arg);`. The whole point of a function like `printf` instead of `puts` is that *it* will substitute into the format string after you call it. Or you could leave extra space at the end of a string for you to store stuff, and then call `puts` instead of `printf`. (Note that `puts` implicitly appends a newline.) Anyway, you should `ret` from main instead of making an exit `syscall`, or use `sys_write`. – Peter Cordes Nov 06 '18 at 04:03